Multilanguage in react using redux - reactjs

I'm new to React (but I already made a simple app with ReactNative). I made a simple web app with few components to make a user login. The problem is that it must support multilang and I can't totally understand how to use redux in order to change the system language from the child component 'Menu' to all the components that are or will be loaded inside the app.
Here are the main components:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<App />,
document.getElementById('root')
);
App.js
import React, {Component} from 'react';
import { BrowserRouter as Router, Route, Link, Redirect } from "react-router-dom";
import Globals from './globals/globals.js';
import './assets/css/main.css';
import Menu from './components/Menu.js';
import Footer from './components/Footer.js';
import Loading from './components/Loading.js';
import Login from './pages/Login.js';
import Home from './pages/Home.js';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
language: "en",
accessToken: "",
isLogged: undefined,
}
}
componentDidMount(props) {
// Get access token if stored
let accessToken = localStorage.getItem('accessToken');
if ( accessToken !== undefined && accessToken !== null && accessToken !== '' ) {
// Try to contact the server to see if it's still viable
} else {
// Go to the login page because you're certainly not logged
localStorage.setItem( 'accessToken', "" );
this.setState({
accessToken: "",
isLogged: false,
});
}
}
render() {
let redirect;
if ( this.state.isLogged === false ) {
redirect = <Redirect to={{ pathname: '/login' }} />;
}
let pages;
if ( this.state.isLogged === undefined ) {
pages = <Loading/>;
} else {
pages = <div>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
</div>;
}
return(
<Router>
<div className="page-wrapper">
<Menu />
<div className="site-content">
{pages}
{redirect}
</div>
<Footer />
</div>
</Router>
);
}
}
Menu.js
import React, { Component } from 'react';
import logo from './../assets/img/logo.png';
export default class Menu extends Component {
constructor(props) {
super(props);
this.state = {
language: "en",
menuState: 0,
}
}
toggleMenu() {
this.setState({
menuState: 1 - this.state.menuState
});
}
changeLanguage(language) {
alert('change language');
}
render() {
return(
<header>
<div className="menu-bar">
<div className="top-bar">
<div className="icon open" onClick={this.toggleMenu.bind( this )}></div>
<div className="logo-wrapper">
<img src={logo} alt="logo" />
</div>
<div className="language-selection-wrapper"></div>
</div>
<div className={this.state.menuState === 1 ? "menu-body opened" : "menu-body closed"}>
<div className="menu-sidebar">
<div className="sidebar-content">
<div className="sidebar-top-bar">
<div className="icon close" onClick={this.toggleMenu.bind( this, 1 )}></div>
<div className="logo-wrapper">
<img src={logo} alt="logo" />
</div>
</div>
<div className="language-selection-wrapper">
<div className={this.state.language === 'it' ? "language current" : "language"} onClick={this.changeLanguage.bind(this, 'it')}>IT</div>
<div className={this.state.language === 'en' ? "language current" : "language"} onClick={this.changeLanguage.bind(this, 'en')}>EN</div>
<div className={this.state.language === 'de' ? "language current" : "language"} onClick={this.changeLanguage.bind(this, 'de')}>DE</div>
</div>
</div>
</div>
</div>
</div>
</header>
);
}
}
And at the end Login.js
import React, { Component } from 'react';
import Globals from './../globals/globals.js';
import Loading from './../components/Loading.js';
import 'font-awesome/css/font-awesome.min.css';
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
language: "en",
loading: false
}
}
componentDidMount(){
document.title = "Login"
}
doLogin() {
alert('Fai il login');
this.setState({
loading: true
});
}
render() {
let loading;
if ( this.state.loading === true ) {
loading = <Loading/>;
}
return(
<div className="login-box">
<div className="welcome-message">
{Globals.messages.welcome[this.state.language]}
</div>
<div className="input-wrapper">
<input type="text" name="username" placeholder={Globals.placeholders.email[this.state.language]} />
</div>
<div className="input-wrapper">
<input type="password" name="password" placeholder={Globals.placeholders.password[this.state.language]} />
</div>
<div className="input-wrapper">
<button type="button" onClick={this.doLogin.bind(this)}><i className="fa fa-sign-in"></i><span>{Globals.placeholders.login[this.state.language]}</span></button>
</div>
{loading}
</div>
);
}
}
I'm also giving the globals.js file with translations
const Globals = {
baseUrl: "https://www.mywebsite.it/webservices/1.0/",
messages: {
welcome: {
it: "Benvenuto!",
en: "Welcome!",
de: "Willkommen!",
},
},
placeholders: {
email: {
it: "Email",
en: "Email",
de: "Email",
},
password: {
it: "Password",
en: "Password",
de: "Password",
},
login: {
it: "Login",
en: "Login",
de: "Login",
},
},
}
export default Globals;

you do not need Redux for internationalization.
Take a look at:
https://github.com/formatjs/react-intl
That's is the industry default for internationalization.

Related

How do I display Logut button once I login to the main UI?

I am trying to implement this feature in my React JS app where if I login successfully, the UI would display the Logout button in the navbar. But if I click on the Logout, I would be logged out from the main UI and redirected to the Login Page where the navbar won't have any Logout Button. Currently, when I log in to the main UI successfully, then I have to refresh the browser tab to show the logout button. It does not appear automatically once I log in successfully.
This is my header Component:
import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import AuthenticationService from "../Login/AuthenticationService";
class HeaderComponent extends Component {
render() {
const isUserLoggedIn = sessionStorage.getItem("authenticatedUser");
console.log(isUserLoggedIn);
return (
<nav className="navbar navbar-expand-lg ">
<Router>
<div className="container-fluid">
<a className="navbar-brand" href="#">
<span className="header-title">TODO APP</span>
</a>
<ul className="navbar-nav d-flex flex-row ms-auto me-3">
{isUserLoggedIn && (
<Link
to="/login"
onClick={() => {
window.location.href = "/login";
}}
>
{" "}
<button
className="btn btn-success logout-button"
onClick={AuthenticationService.logout}
>
Logout
</button>
</Link>
)}
</ul>
</div>
</Router>
{" "}
</nav>
);
}
}
export default HeaderComponent;
The isUserLoggedIn is a boolean value that is retrieved from the session storage. If isUserLoggedIn is true then the Logout button would be displayed on the Navbar.
const isUserLoggedIn = sessionStorage.getItem("authenticatedUser");
The AuthenticationService.js file is:
import React, { Component } from "react";
class AuthenticationService extends Component {
registerSuccessfulLogin(username, password) {
console.log("Login Successful");
sessionStorage.setItem("authenticatedUser", username);
console.log(sessionStorage.getItem("authenticatedUser"));
}
isUserLoggedIn() {
let user = sessionStorage.getItem("authenticatedUser");
if (user === null) {
return false;
} else {
return true;
}
// return true;
}
logout() {
sessionStorage.removeItem("authenticatedUser");
}
getLoggedInUserName() {
let user = sessionStorage.getItem("authenticatedUser");
if (user === null) return "";
return user;
}
}
export default new AuthenticationService();
The App.js component is:
import "./App.css";
import DropDownMenu from "./components/DropdownMenu/DropDownMenu";
import HeaderComponent from "./components/Header/HeaderComponent";
import LoginComponent from "./components/Login/LoginComponent";
import {
BrowserRouter as Router,
Routes,
Route,
useParams,
Link,
} from "react-router-dom";
import "./styles.css";
import "./loginStyle.css";
import "./Header.css";
import ErrorComponent from "./components/search-options/ErrorComponent";
import AuthenticatedRoute from "./components/DropdownMenu/AuthenticatedRoute";
function App() {
return (
<div className="App">
<HeaderComponent />
<Router>
<Routes>
<Route path="/" element={<LoginComponent />}></Route>
{/* <Route path="/login" element={<Navigate to="/LoginComponent" />} /> */}
<Route path="/login" default element={<LoginComponent />}></Route>
<Route
path="/pst"
element={
<AuthenticatedRoute>
<DropDownMenu />
</AuthenticatedRoute>
}
></Route>
<Route path="*" element={<ErrorComponent />}></Route>
</Routes>
</Router>
</div>
);
}
export default App;
I am not sure why do I have to refresh the Tab to show the Logout button on to the NavBar.
EDIT
I have added the Login component for further reference:
import axios from "axios";
import { data } from "jquery";
import React, { Component } from "react";
import { useNavigate } from "react-router";
import App from "../../App";
import HeaderComponent from "../Header/HeaderComponent";
import GetUserIp from "../tracking/GetUserIp";
import TrackLoginActivity from "../tracking/TrackLoginActivity";
import AuthenticationService from "./AuthenticationService";
class LoginComponent extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
ipAddress: "",
hasLoginFailed: false,
isUserLoggedIn: false,
};
this.handleCredentialChange = this.handleCredentialChange.bind(this);
this.submitLogin = this.submitLogin.bind(this);
}
handleCredentialChange(event) {
console.log(event.target.name);
this.setState({ [event.target.name]: event.target.value });
}
submitLogin(event) {
event.preventDefault();
var session_url =
"login check api url";
GetUserIp.retrieveIpAddress().then((response) => {
this.setState({ ipAddress: response.data.ip });
});
console.log(this.state.ipAddress);
axios
.post(
session_url,
{},
{
auth: {
username: this.state.username,
password: this.state.password,
},
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Authenticated");
console.log(this.props);
AuthenticationService.registerSuccessfulLogin(
this.state.username,
this.state.password
);
this.props.navigate(`/pst`);
//track user login activity into the DB Entity, smart_tool_login_logs
TrackLoginActivity.trackSuccessfulLogin(
this.state.username,
this.state.ipAddress
);
})
.catch((error) => {
console.log("Error on autheication");
this.setState({ hasLoginFailed: true });
});
}
render() {
return (
<div className="login-app">
<form action="" className="login-form" onSubmit={this.submitLogin}>
<div className="container">
<input
type="text"
placeholder="username"
name="username"
className="username-value"
maxLength={30}
autoComplete="on"
value={this.state.username}
onChange={this.handleCredentialChange}
/>
<input
type="password"
placeholder="password"
name="password"
className="password-value"
maxLength={30}
autoComplete="on"
value={this.state.password}
onChange={this.handleCredentialChange}
/>
{this.state.hasLoginFailed && (
<div className="login-fail-message">
Invalid username/password
</div>
)}
<div className="login-btn"></div>
<button className="btn btn-success login-btn" type="submit">
Login
</button>
</div>
</form>
</div>
);
}
}
function WithNavigate(props) {
let navigate = useNavigate();
return <LoginComponent {...props} navigate={navigate} />;
}
export default WithNavigate;
Your header component is a stateless component, it has neither props nor internal state, so it is only rendered once with the initial value of isUserLoggedIn.
If you want the header component to react to the login status, it needs to be notified in some way that the value has changed. The easiest way to do so is to store this information in the state of your App component, then passing it down as a prop to the HeaderComponent.
// App.js
import "./App.css";
import DropDownMenu from "./components/DropdownMenu/DropDownMenu";
import HeaderComponent from "./components/Header/HeaderComponent";
import LoginComponent from "./components/Login/LoginComponent";
import {
BrowserRouter as Router,
Routes,
Route,
useParams,
Link,
} from "react-router-dom";
import "./styles.css";
import "./loginStyle.css";
import "./Header.css";
import ErrorComponent from "./components/search-options/ErrorComponent";
import AuthenticatedRoute from "./components/DropdownMenu/AuthenticatedRoute";
import AuthenticationService from "../Login/AuthenticationService";
function App() {
const [isUserLoggedIn, setIsUserLoggedIn] = useState(AuthenticationService.isUserLoggedIn()) // use the session storage to get the initial state's value
function onLoginSuccessful() {
setIsUserLoggedIn(true); // update the state to notify React the value has changed
}
return (
<div className="App">
<HeaderComponent isUserLoggedIn={isUserLoggedIn} /> {/* pass down the state value as a prop */}
<Router>
<Routes>
<Route path="/" element={<LoginComponent onLoginSuccessful={onLoginSuccessful}/>}></Route>
{/* <Route path="/login" element={<Navigate to="/LoginComponent" />} /> */}
<Route path="/login" default element={<LoginComponent onLoginSuccessful={onLoginSuccessful} />}></Route>
<Route
path="/pst"
element={
<AuthenticatedRoute>
<DropDownMenu />
</AuthenticatedRoute>
}
></Route>
<Route path="*" element={<ErrorComponent />}></Route>
</Routes>
</Router>
</div>
);
}
export default App;
// HeaderComponent.js
import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import AuthenticationService from "../Login/AuthenticationService";
class HeaderComponent extends Component {
render() {
const isUserLoggedIn = this.props.isUserLoggedIn; // retrieve the value from the props
console.log(isUserLoggedIn);
return (
<nav className="navbar navbar-expand-lg ">
<Router>
<div className="container-fluid">
<a className="navbar-brand" href="#">
<span className="header-title">TODO APP</span>
</a>
<ul className="navbar-nav d-flex flex-row ms-auto me-3">
{isUserLoggedIn && (
<Link
to="/login"
onClick={() => {
window.location.href = "/login";
}}
>
{" "}
<button
className="btn btn-success logout-button"
onClick={AuthenticationService.logout}
>
Logout
</button>
</Link>
)}
</ul>
</div>
</Router>
{" "}
</nav>
);
}
}
export default HeaderComponent;
Note that you also have to pass a callback to LoginComponent to be called once the user successfully logs in. Using state updates, React gets notified that the value of isUserLoggedIn has changed and will re-render the components that depend on this value, including HeaderComponent.
EDIT: I updated the implementation of LoginComponent with the callback I mentionned
// LoginComponent.js
import axios from "axios";
import { data } from "jquery";
import React, { Component } from "react";
import { useNavigate } from "react-router";
import App from "../../App";
import HeaderComponent from "../Header/HeaderComponent";
import GetUserIp from "../tracking/GetUserIp";
import TrackLoginActivity from "../tracking/TrackLoginActivity";
import AuthenticationService from "./AuthenticationService";
class LoginComponent extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
ipAddress: "",
hasLoginFailed: false,
isUserLoggedIn: false,
};
this.handleCredentialChange = this.handleCredentialChange.bind(this);
this.submitLogin = this.submitLogin.bind(this);
}
handleCredentialChange(event) {
console.log(event.target.name);
this.setState({ [event.target.name]: event.target.value });
}
submitLogin(event) {
event.preventDefault();
var session_url =
"login check api url";
GetUserIp.retrieveIpAddress().then((response) => {
this.setState({ ipAddress: response.data.ip });
});
console.log(this.state.ipAddress);
axios
.post(
session_url,
{},
{
auth: {
username: this.state.username,
password: this.state.password,
},
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Authenticated");
console.log(this.props);
AuthenticationService.registerSuccessfulLogin(
this.state.username,
this.state.password
);
// add this line to your `LoginComponent` so that
// onLoginSuccessul is called when user is logged in
this.props.onLoginSuccessful();
this.props.navigate(`/pst`);
//track user login activity into the DB Entity, smart_tool_login_logs
TrackLoginActivity.trackSuccessfulLogin(
this.state.username,
this.state.ipAddress
);
})
.catch((error) => {
console.log("Error on autheication");
this.setState({ hasLoginFailed: true });
});
}
render() {
return (
<div className="login-app">
<form action="" className="login-form" onSubmit={this.submitLogin}>
<div className="container">
<input
type="text"
placeholder="username"
name="username"
className="username-value"
maxLength={30}
autoComplete="on"
value={this.state.username}
onChange={this.handleCredentialChange}
/>
<input
type="password"
placeholder="password"
name="password"
className="password-value"
maxLength={30}
autoComplete="on"
value={this.state.password}
onChange={this.handleCredentialChange}
/>
{this.state.hasLoginFailed && (
<div className="login-fail-message">
Invalid username/password
</div>
)}
<div className="login-btn"></div>
<button className="btn btn-success login-btn" type="submit">
Login
</button>
</div>
</form>
</div>
);
}
}
function WithNavigate(props) {
let navigate = useNavigate();
return <LoginComponent {...props} navigate={navigate} />;
}
export default WithNavigate;

Going to another page in ReactJS

I am attempting to learn reactjs and I've looked up so many different resources from using react-route to react-route-dom but everything I've tried doesn't work as everything says it does so I am not sure what I am misssing.
I have a class component called LoginForm which renders the form and handles all of the logic for submitting to API and handling the response.
The api request is working and I successfully check that the login is valid, I then want to redirect to another page called dashboard.html.
Below is my component class
import React from 'react'
import * as api from '../JSFuncs/APIManager'
import 'react-router-dom'
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
show_notice: false,
error_msg: ''
};
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleUsernameChange(event) {
this.state.username = event.target.value;
this.setState(this.state);
}
handlePasswordChange(event) {
this.state.password = event.target.value;
this.setState(this.state);
}
handleSubmit(event) {
event.preventDefault();
this.props.history.push("dashboard.html");
this.state.show_notice = true;
this.setState(this.state);
const postArray = {
username: this.state.username,
password: this.state.password
};
let comp = this;
api.sendRequest(postArray, "admin/authenticator.php", "submitLogin").then(function(result){
alert(JSON.stringify(result));
if (result.result === 0)
{
if (result.data === 0) //Login OK
{
comp.history.pushState(null, 'dashboard.html');
//comp.props.history.push('/dashboard.html');
}
comp.setState(comp.state);
}
else
{
comp.state.password = '';
comp.state.error_msg = 'An error occurred with the DB';
comp.setState(comp.state);
}
comp.state.show_notice = true;
comp.setState(comp.state);
})
}
render() {
const style = this.state.show_notice === false ? {display: 'none'} : {};
const { location, history } = this.props
return (
<section className="h-100">
<div className="container h-100">
<div className="d-flex align-items-center justify-content-center h-100">
<div className="d-flex flex-column align-self-center">
<LoginStatus style={style} error_msg={this.state.error_msg} />
<form onSubmit={this.handleSubmit} className='form-horizontal align-self-center'>
<div className='form-group row'>
<label htmlFor='txtUsername' className='col-sm-2 col-form-label'>Username: </label>
<div className='col-sm-9'>
<input type='text' className='form-control' id='txtUsername' value={this.state.username}
placeholder='Your Username' onChange={this.handleUsernameChange}/>
</div>
</div>
<div className='form-group row'>
<label htmlFor='txtPassword' className='col-sm-2 col-form-label'>Password: </label>
<div className='col-sm-9'>
<input type='password' className='form-control' id='txtPassword' value={this.state.password}
placeholder='Your password' onChange={this.handlePasswordChange}/>
</div>
</div>
<div className='formButtonContainer'>
<button className='btn-primary'>Login</button>
</div>
</form>
</div>
</div>
</div>
</section>
);
}
}
class LoginStatus extends React.Component
{
render(){
const className = this.props.error_msg === '' ? 'alert-info' : 'alert-warning';
const msg = this.props.error_msg === '' ? 'You\'ve successfully logged in' : this.props.error_msg;
return(
<div style={this.props.style} className={'alert ' + className}>
{msg}
</div>
)
}
}
export default LoginForm
In the response of handleSubmit I check if the login result is 0 and then I am using comp.history.pushState (comp is declared to be this so its in scope of the promise).
I've tried pushState and push from other examples, but I get the same type of error. I've also tried comp.state.history.push but no luck. I login successfully and show the alert box when I do the history push I get the following:
TypeError: Cannot read property 'push' of undefined
I'm very new to react so apologise if this is a simple answer but I can't seem to get my hand around how this works from everything I've googled.
In your App.js you should manage pages with routes:
import {BrowserRouter, Route, Switch} from "react-router-dom";
import { createBrowserHistory } from "history";
import {LoginForm} from './components/LoginForm';
import {Dashboard} from './components/Dashboard';
const history = createBrowserHistory();
class App extends Component {
constructor(props) {
super(props);
console.log(props)
}
render() {
path="/" is your home or main page
path="/dashboard" is your dashboard
return (
<BrowserRouter>
<div>
<Switch>
<Route path="/" render={(props) => <LoginForm props={history} {...props} /> } exact />
<Route path="/dashboard" render={(props) => <Dashboard props={history} {...props} /> }/>
</Switch>
</div>
</BrowserRouter>
)
then in your LoginForm you can
export class LoginForm extends Component {
constructor(props) {
super(props);
console.log(props)
}
go_dashboard = (e) => {
this.props.history.push("/dashboard");
}
This will then Switch to your Dashboard component.

Not able to open screen in reactjs.Routing not working

I am new to react and trying below link to get started.
https://jasonwatmore.com/post/2018/09/11/react-basic-http-authentication-tutorial-example
But, my screen is not showing any thing and there is not such error on CLI after npm start.
Below is index.js.
import React from 'react';
import { render } from 'react-dom';
import { App } from './App/App.js';
// setup fake backend
import { configureFakeBackend } from './_helpers/fake-backend.js';
configureFakeBackend();
render(
<App />,
document.getElementById('app')
);
App.js
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { PrivateRoute } from '../_components/PrivateRoute.js';
import { HomePage } from '../HomePage/Homepage.js';
import { LoginPage } from '../LoginPage';
class App extends React.Component {
render() {
return (
<div className="jumbotron">
<div className="container">
<div className="col-sm-8 col-sm-offset-2">
<Router>
<div>
<PrivateRoute path="/" exact component={HomePage} />
<Route path="/login" exact component={LoginPage} />
</div>
</Router>
</div>
</div>
</div>
);
}
}
export { App };
It is just opening a blank half opened screen.
Below is CLI screen shot.
Below are home and login.js code.
import React from 'react';
import { Link } from 'react-router-dom';
import { userService } from '../_services/user.service.js';
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {},
users: []
};
}
componentDidMount() {
this.setState({
user: JSON.parse(localStorage.getItem('user')),
users: { loading: true }
});
userService.getAll().then(users => this.setState({ users }));
}
render() {
const { user, users } = this.state;
return (
<div className="col-md-6 col-md-offset-3">
alert("I am 2nd here");
<h1 >Hi {user.firstName}!</h1>
<p>You're logged in with React & Basic HTTP Authentication!!</p>
<h3>Users from secure api end point:</h3>
{users.loading && <em>Loading users...</em>}
{users.length &&
<ul>
{users.map((user, index) =>
<li key={user.id}>
{user.firstName + ' ' + user.lastName}
</li>
)}
</ul>
}
<p>
<Link to="/login">Logout</Link>
</p>
</div>
);
}
}
export { HomePage };
And output screen is :

New Component is returned but the previous component stays the same in ReactJs

A new component is returned after login, but both the login component and the Home Component are seen on the page. I need to return the Home Componenet without Login Component. I am new to React and still trying to understand return and routes in React.
This is my pages component which returns either Login or Home based on this.state.redirect1.
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import '../../App.css';
import Login from '../Login';
import Home from '../Home';
import Header from './Header';
import Footer from './Footer';
class Pages extends Component {
constructor(props) {
super(props)
this.state = {
redirect: false,
}
}
handleClick() {
this.state.redirect = true;
console.log(this.state.redirect);
}
changeRedirect =() =>{
this.state.redirect = true;
console.log(this.state.redirect);
this.forceUpdate()
}
renderRedirect = () => {
if(this.props.redirect1){
return <Home/>
}
else{
return <Login/>
}
}
render() {
return (
<div className="mh-100 PgWidth">
{this.renderRedirect()}
</div>
)
}
}
export default Pages
Below is my Login, Home and App Components
Login.js
import React, { Component } from 'react'
import Axios from 'axios';
import Pages from './common/Pages'
import { Redirect } from 'react-router-dom';
class Login extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
password: '',
redirect: false
}
}
handleUsername = (event) => {
this.setState({
username: event.target.value
})
}
handlePassword = (event) => {
this.setState({
password: event.target.value
})
}
renderRedirect = () => {
if (this.state.redirect) {
console.log("from render redirect");
return <Pages redirect1={this.state.redirect} />
}
}
formSubmitHandler = event => {
let formdata = new FormData();
formdata.append("username", this.state.username);
formdata.append("password", this.state.password);
Axios.post("/auth/local",{
"name":this.state.username,
"password": this.state.password
})
.then(res => {
if (res) {
console.log(res);
this.setState({ redirect: true });
}
})
event.preventDefault() // used to keep the form data as entered even after the submit
}
render() {
const { username, password } = this.state
return (
<div className="p-5">
{ this.renderRedirect() }
<h3>Sign-In</h3>
<form onSubmit={this.formSubmitHandler}>
<div className="form-group row">
<label htmlFor="inputEmail3" className="col-sm-2 col-form-label">Username</label>
<div className="col-sm-10">
<input type="text" value={username} onChange={this.handleUsername}
className="form-control" id="inputEmail3" placeholder="Username" />
</div>
</div>
<div className="form-group row">
<label htmlFor="inputPassword3" className="col-sm-2 col-form-label">Password</label>
<div className="col-sm-10">
<input type="password" value={password} onChange={this.handlePassword}
className="form-control" id="inputPassword3" placeholder="Password" />
</div>
</div>
<div className="form-group row">
<div className="col-sm-2">Checkbox</div>
<div className="col-sm-10">
<div className="form-check">
<input className="form-check-input" type="checkbox" id="gridCheck1" />
<label className="form-check-label" htmlFor="gridCheck1">
Example checkbox
</label>
</div>
</div>
</div>
<div className="form-group row">
<div className="col-sm-10">
<button type="submit" onClick={this.formSubmitHandler} className="btn btn-primary">Sign in</button>
</div>
</div>
</form>
</div>
)
}
}
export default Login
Home.js
import React, { Component } from 'react'
import '../App.css';
export class Home extends Component {
componentDidMount(){
console.log("home component mount");
}
render() {
return (
<div>
<h1>The page has been routed</h1>
</div>
);
}
}
export default Home
App.js
import React, { Component } from 'react';
import './App.css';
import Header from './components/common/Header';
import Footer from './components/common/Footer';
import Pages from './components/common/Pages';
class App extends Component {
render() {
return (
<div className="App container-fluid bg-light w-75">
<div className="row justify-content-md-center">
<div className="col m-0 p-0">
<Header/>
<div className="">
<Pages/>
</div>
<Footer/>
</div>
</div>
</div>
);
}
}
export default App;
Issue is in this line:
{ this.renderRedirect() }
Once redirect will be true, it will render the Home page first then the Login component.
Solution to you problem is: Manage the redirect bool in Page component only, and pass a function to update to Login component to update its value and decide the component based on that.
Changes:
1- defined redirect: false in Pages component.
2- A function to change its value in Pages component:
updateValue = (value) => {
this.setState({ redirect: true })
}
3- Pass function to Login component:
renderRedirect = () => {
if(this.props.redirect1) {
return <Home/>
}
else{
// =====> here
return <Login updateValue={this.updateValue} />
}
}
4- After successful Login call this function and render Home Component:
formSubmitHandler = event => {
event.preventDefault();
let formdata = new FormData();
formdata.append("username", this.state.username);
formdata.append("password", this.state.password);
Axios.post("/auth/local",{
"name":this.state.username,
"password": this.state.password
})
.then(res => {
if (res) {
// =======> here
this.props.updateValue(true)
}
})
}
5- Remove this line from Login Component:
{ this.renderRedirect() }
Problem with current code:
You are managing the login session using state variable, so after refreshing the page it will again show the login page not home page. So better to store the value in localStorage and read its value in page component to decide the initial value of redirect.
Suggestion:
Instead of deciding the route/component using boolean, better to use react-router for better structuring/managing the app.
Try return it in render:
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import '../../App.css';
import Login from '../Login';
import Home from '../Home';
import Header from './Header';
import Footer from './Footer';
class Pages extends Component {
constructor(props) {
super(props)
this.state = {
redirect: false,
}
}
handleClick() {
this.state.redirect = true;
console.log(this.state.redirect);
}
changeRedirect =() =>{
this.state.redirect = true;
console.log(this.state.redirect);
this.forceUpdate()
}
render() {
if(this.props.redirect){
return (
<div className="mh-100 PgWidth">
<Home/>
</div>
)
} else {
return (
<div className="mh-100 PgWidth">
<Login/>
</div>
)
}
}
export default Pages;
You can do it like this
<div className="mh-100 PgWidth">
{this.props.redirect1&&<Home/>}
{!this.props.redirect1&&<Login />}
</div>
But, the best way to do this is using react router and managing the global react state

Redirect doesn't redirect to components

This is my index.js page
import React from 'react';
import ReactDOM from 'react-dom';
import Login from './Login';
import Dashboard from './Dashboard';
import { BrowserRouter as Router, Route} from 'react-router-dom';
import './css/bootstrap.min.css';
import './css/font-awesome.min.css';
import './css/style.css';
import { createHistory, useBasename } from 'history'
const history = useBasename(createHistory)({
basename: '/'
})
ReactDOM.render((
<Router history={history}>
<div>
<Route path="/" component={Login} />
<Route path="dashboard" component={Dashboard} store={Dashboard} />
<Route exact path="login" component={Login} store={Login} />
</div>
</Router>
),
document.getElementById('root')
);
This is my login page. But clicking on the button doesn't redirect to the corresponding component.
import React, { Component } from 'react';
export default class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : ''
};
}
login(){
//this.props.router.push('/dashboard'); // Its was not working
this.props.history.push('dashboard'); //Its working for me
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
In your case this.props.router would be undefined. Here's a rough solution that I made. Reading the comments in the code will help.
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom'; // add this import
export default class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : '',
redirectToReferrer: true // when you're checking if the user is authenticated you have to keep this false
};
}
// componentWillReceiveProps(nextProps) {
// if ( put your authentication logic here ) {
// this.setState({ redirectToReferrer: true });
// }
// }
login(){
this.props.history.push('/dashboard');
}
render() {
const from = { pathname: '/dashboard' };
const { redirectToReferrer } = this.state; // redirectToReferrer is true in the initial state
if (redirectToReferrer) { // if true the user will be redirected to /dashboard
return <Redirect to={from} />;
}
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
In React 16 and above you can use Redirect from 'react-router-dom'
import { Redirect } from 'react-router-dom'
Define state in your component
this.state = {
loginStatus:true
}
than in your render method
render () {
if(this.state.loginStatus){
return <Redirect to='/home' />
}
return(
<div> Please Login </div>
)
}
Make use of withRouter frun react-router to inject router as a prop to your login component
import React, { Component } from 'react';
import {withRouter} from 'react-router'
import $ from 'jquery';
class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : ''
};
}
login(){
this.props.history.push('/dashboard');
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default withRouter(Login)

Resources