'this.props.displaychange is not a function' when I use Route - reactjs

*Sorry in advance I couldn't split the code into separate components in the post
I have a question that I will be able to explain well
I have an authentication component that receives a prop from another component
Now when I put all the components under one big parent component that contains all the components everything works fine and the props pass successfully
But as soon as I start using route I get this message
"Uncaught (in promise) TypeError: this.props.displaychange is not a function"
whet I tried to do here is to change the state in the TeamList component (state.displayTeams to true)
import './App.css';
import React from 'react'
import { Route, Routes } from 'react-router-dom'
import Home from './components/Home/Home';
import LogIn from './components/Log-in/Log-in';
import SignIN from './components/Sign-in/Sign-in';
import TeamList from './components/Team-list/Team-list';
import TeamDisplay from './components/TeamDisplay/TeamDisplay';
function App() {
return (
<div>
<Routes>
<Route path='/' exact element={<Home />} />
<Route path='/login' element={<LogIn />} />
<Route path='/sign-in' element={<SignIN />} />
<Route path='/teamlist' element={<TeamList />} />
<Route path='/teamdisplay' element={<TeamDisplay />} />
</Routes>
</div>
);
}
export default App;
import React, { Component } from "react";
import { signInWithEmailAndPassword, signOut } from 'firebase/auth'
import { auth } from '../../firebase-config'
import './Log-in.css'
import { Link } from "react-router-dom";
class LogIn extends Component {
state = {
logEmail: '',
logPass: '',
user: '',
login: false
}
login = async (displaychange, e) => {
e.preventDefault()
this.setState({ login: true })
const user = await signInWithEmailAndPassword(auth, this.state.logEmail, this.state.logPass)
console.log(user.user.email)
this.setState({ user: user.user.email })
this.setState({ logEmail: '', logPass: '' })
console.log('logged in')
this.props.displaychange()
}
logOut = async (displaychangeOut, e) => {
e.preventDefault()
if (this.state.login) {
await signOut(auth)
this.setState({ user: '', logEmail: '', logPass: '' })
console.log('you out')
this.props.displaychangeOut()
} else {
return
}
}
render() {
return (
<div className="Login-form">
<form>
<span>ACCOUNT LOGIN</span>
<label>USERNAME </label>
<input value={this.state.logEmail} onChange={(e) => this.setState({ logEmail: e.target.value })} name="nameLog" placeholder="Your name..." />
<label>PASSWORD </label>
<input value={this.state.logPass} onChange={(e) => this.setState({ logPass: e.target.value })} name="passLog" placeholder="Your password..." />
<button onClick={(e) => this.login(this.props.displaychange, e)}>LOG IN</button>
</form>
</div>
)
}
}
export default LogIn
import React, { Component } from "react";
import { db } from '../../firebase-config'
import { collection, addDoc, getDocs, getDoc, doc } from 'firebase/firestore'
import TeamDisplay from "../TeamDisplay/TeamDisplay";
import LogIn from "../Log-in/Log-in";
const teamCollectionRef = collection(db, 'Teams')
class TeamList extends Component {
state = {
teams: [
],
displayTeams: false
}
componentDidMount() {
getDocs(teamCollectionRef)
.then(snap => {
let teams = []
snap.docs.forEach(doc => {
teams.push({ ...doc.data() })
});
this.setState({ teams: teams });
});
}
changedisplay = () => {
this.setState({ displayTeams: true })
}
changedisplayOut = () => {
this.setState({ displayTeams: false })
}
render() {
let displayTeam
if (this.state.displayTeams) {
displayTeam = this.state.teams.map(item => <TeamDisplay key={item.teamId} team={item} />)
} else {
displayTeam = null
}
return (
<div>
{displayTeam}
</div>
)
}
}
export default TeamList

Related

Undefined function in React Router + Redux

Currently writing application in React + Redux stack. During development, I hit the problem where in one's of React component, Redux function work just fine and in index.js throwing that Redux function is undefined.
What I wish to do, is to keep user sign in between reloading of web page. So where pages reload, componentDidMonut function in index.js check if there is a token in localstorage then send one api call to check if JWT token did not expired. And if everthing is correct call redux function signIn() to rerender app.
In Login component login working and redirect to after sign in, unfortunately in index.js React throwing error:
.
After checking in console this function is simply undefined, and I don't know why.
Looking forward for pointing mistakes I made. Thanks in advance
Below code:
actions/index.js:
export const signIn = () => {
return {
type: "SIGN_IN"
};
};
export const signOut = () => {
return {
type: "SIGN_OUT"
};
};
reducers/authReducers:
const INITIAL_STATE = {
isSignedIn: null
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case "SIGN_IN":
return { ...state, isSignedIn: true };
case "SIGN_OUT":
return { ...state, isSignedIn: false };
default:
return state;
}
};
Login.js:
import React from "react";
import {
Button,
Container,
Form,
Grid,
Header,
Message,
Segment
} from "semantic-ui-react";
import { connect } from "react-redux";
import { signIn, signOut } from "../actions";
import api from "../api/api";
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
isSignedIn: null,
email: "",
password: "",
errorMessage: ""
};
this.errorMessageRef = React.createRef();
}
handleLogin = async () => {
try {
const response = await api.login(this.state.email, this.state.password);
if (response.status === 200) {
localStorage.setItem("token", response.data.token);
this.props.signIn();
this.props.history.push("/flat");
}
} catch (error) {
this.errorMessageRef.current.hidden = false;
this.setState({ ...this.state, errorMessage: `${error}` });
this.props.signOut();
}
};
render() {
return (
<Container>
<Grid centered columns={2}>
<Grid.Column>
<Header as="h2" textAlign="center">
Login
</Header>
<Segment>
<Form size="large">
<Form.Input
fluid
icon="user"
iconPosition="left"
placeholder="Email address"
onChange={event =>
this.setState({ email: event.target.value })
}
/>
<Form.Input
fluid
icon="lock"
iconPosition="left"
placeholder="Password"
type="password"
onChange={event =>
this.setState({ password: event.target.value })
}
/>
<Button
color="blue"
fluid
size="large"
onClick={this.handleLogin}
>
Login
</Button>
</Form>
</Segment>
<Message ref={this.errorMessageRef} negative={true} hidden={true}>
Email or password and incorrect
</Message>
<Message>
Not registered yet? Sign Up
</Message>
</Grid.Column>
</Grid>
</Container>
);
}
}
export default connect(null, { signIn, signOut })(Login);
index.js:
import React from "react";
import { createStore } from "redux";
import ReactDOM from "react-dom";
import { connect, Provider } from "react-redux";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { Container } from "semantic-ui-react";
import reducers from "./reducers";
import { signIn, signOut } from "./actions";
import api from "./api/api";
import Login from "./components/Login";
import App from "./components/pages/App.js";
import Flat from "./components/pages/Flat";
import NavBar from "./components/NavBar";
import Duties from "./components/pages/Duties";
import MyDuties from "./components/pages/MyDuties";
import CreateFlat from "./components/flat/CreateFlat";
import JoinFlat from "./components/flat/JoinFlat";
import Payments from "./components/pages/Payments";
import "./components/index.css";
const store = createStore(reducers);
class Routing extends React.Component {
constructor(props) {
super(props);
this.state = { isSignedIn: null };
}
componentDidMount() {
this.isLoggedIn();
}
isLoggedIn = async () => {
try {
if (localStorage.getItem("token") != null) throw "user not sign in";
await api.getCurrentFlatmate();
this.props.signIn();
} catch (e) {
this.props.signOut();
}
};
render() {
return (
<Router>
<NavBar />
<Switch>
<Route exact path="/" component={App} />
<Route path="/home" component={App} />
<Route path="/sign-in" component={Login} />
<Route path="/sign-out" component={App} />
<Route path="/user" component={Login} />
<Route path="/flat" component={Flat} />
<Route path="/join-flat" component={JoinFlat} />
<Route path="/create-flat" component={CreateFlat} />
<Route path="/duties" component={Duties} />
<Route path="/my-duties" component={MyDuties} />
<Route path="/payments" component={Payments} />
</Switch>
</Router>
);
}
}
export default connect(null, { signIn, signOut })(Routing);
ReactDOM.render(
<Provider store={store}>
<Routing />
</Provider>,
document.getElementById("root")
);
Try using this.props.dispatch(signOut()) instead of this.props.signOut().
And in the same way for signIn()

problem with router and privaterouter / history

Hello I have a problem redirecting to a page doing a verification on a privaterouter
Unhandled Rejection (TypeError): Cannot read property 'push' of
undefined
on this line:
this.props.history.push ("/ home");
my component:
import React, { Component } from 'react';
import api from '../services/api';
import { withRouter } from 'react-router';
class LoginForm extends Component {
constructor(props){
super(props);
this.state = {
login:'',
password:'',
};
this.onSubmit = this.onSubmit.bind(this);
this.onChange = this.onChange.bind(this);
}
async onSubmit(e){
e.preventDefault();
const {login, password } = this.state;
const response = await api.post('/login', { login,password });
const user = response.data.user.login;
const {jwt} = response.data;
localStorage.setItem('token', jwt);
localStorage.setItem('user', user);
this.props.history.push("/home");
}
onChange(e){
this.setState({[e.target.name]: e.target.value});
}
render() {
const { errors, login, password, isLoading } = this.state;
return (
<form onSubmit={this.onSubmit}>
<label htmlFor="login">Login</label>
<input type="text" name="login" id="login" value={login} onChange={(e) => this.onChange(e)} placeholder="Informe seu login" />
<label htmlFor="password">Senha</label>
<input type="password" name="password" id="password" value={password} onChange={(e) => this.onChange(e)} placeholder="Informe sua senha"/>
<button className="btnEnt" type="submit">Entrar</button>
</form>
)
}
}
export default withRouter (LoginForm);
my router:
import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Login from './pages/login/index';
import DashBoard from './pages/dashboard/index';
import PrivateRoute from './auth';
export default function Routes(){
return(
<BrowserRouter>
<div>
<Switch>
<Route path="/" exact component = {Login}/>
<PrivateRoute path="/home" component = {DashBoard}/>
</Switch>
</div>
</BrowserRouter>
);
}
my private route or auth router:
import React from 'react';
import { Route, Redirect} from 'react-router-dom';
const isAuth = () => {
console.log('a');
if(localStorage.getItem('token') !== null) {
console.log('true')
return true;
}
return false;
};
const PrivateRoute = ({component: Component, ...rest}) => {
return (
<Route
{...rest}
render={props =>
isAuth() ? (
<Component {...props} />
): (
<Redirect
to={{
pathname: '/',
state: {message: 'Usuário não autorizado'}
}}
/>
)}
/>
);
}
export default PrivateRoute;
I basically have my router and I also check if the user is allowed to enter this page, but I'm having trouble making it work.
Well, I read your code and here is my answer
You just need import withRouter from react-router-dom and not from react-router ;)
import { withRouter } from "react-router-dom";
And use it like
export default withRouter(LoginForm);

How to pass props in the modal in react

I am creating my first react project, i am using GitHub api to fetch user and display them firstly in card view then on clicking on more button to any profile i want to create a modal using portals in react till now i am able to create an modal but now i am not getting how to get data to that modal coponent
Here is my App.js
import React, { Fragment, Component } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Navbar from './components/layout/Navbar';
import Users from './components/users/Users';
import User from './components/users/User';
import Modal from './components/Modal/Modal'
import Search from './components/users/Search';
import Alert from './components/layout/Alert';
import About from './components/pages/About';
import axios from 'axios';
import './App.css';
class App extends Component {
state = {
users: [],
user: {},
loading: false,
alert: null,
modal: {},
}
// get users from Search.js
searchUsers = async text => {
this.setState({ loading: true })
const res = await axios.get(
`https://api.github.com/search/users?q=${text}&client_id=${
process.env.REACT_APP_GITHUB_CLIENT_ID
}&client_secret=${process.env.REACT_APP_GITHUB_CLIENT_SECRET}`);
this.setState({ users: res.data.items, loading: false })
console.log(text);
}
//get single profile
getUser = async username => {
this.setState({ loading: true })
const res = await axios.get(
`https://api.github.com/users/${username}?client_id=${
process.env.REACT_APP_GITHUB_CLIENT_ID
}&client_secret=${process.env.REACT_APP_GITHUB_CLIENT_SECRET}`);
this.setState({ user: res.data, loading: false });
this.setState({ modal: res.data, loadading: false });
}
//clear search
clearUsers = () => this.setState({ users: [], loading: false });
setAlert = (msg, type) => {
this.setState({ alert: { msg: msg, type: type } });
setTimeout(() => this.setState({ alert: null }), 5000);
};
render() {
return (
<Router>
<div className='App'>
<Navbar />
<div className="container">
<Alert alert={this.state.alert} />
<Switch>
<Route exact path='/'
render={props => (
<Fragment>
<Search
searchUsers={this.searchUsers}
clearUsers={this.clearUsers}
showClear={this.state.users.length > 0 ? true : false}
setAlert={this.setAlert}
/>
<Users loading={this.state.loading} users={this.state.users} />
</Fragment>
)} />
<Route path='/about' component={About} />
<Route path='/user/:login' render={props => (
<User {...props} getUser={this.getUser} user={this.state.user} loading={this.state.loading} />
)} />
<Route path='/modal/:login' render={props => (
<Modal {...props} getUser={this.getUser} modal={this.state.modal} loading={this.state.loading} />
)} />
</Switch>
</div>
</div>
</Router>
);
}
}
export default App;
here is my Modal.js
import React, { Fragment, Component } from 'react';
import ReactDom from 'react-dom';
import Spinner from '../layout/Spinner';
import { Link } from 'react-router-dom';
const modalRoot = document.getElementById('modal');
export default class Modal extends Component {
constructor() {
super();
this.el = document.createElement('div');
}
componentDidMount = () => {
modalRoot.appendChild(this.el);
};
componentWillUnmount = () => {
modalRoot.removeChild(this.el);
};
render() {
const {
children,
name,
avatar_url,
location,
bio,
blog,
followers,
following,
public_repos,
} = this.props.modal;
const { loading } = this.props;
if (loading) return <Spinner />
return (
ReactDom.createPortal(children, this.el)
)
}
}
any guide would be appriciated thanks in advance
You are passing the props already to Modal.
In Modal, do something like
Class Modal extends Component {
constructor(){
super(props);
}
render(){
const {
modal,
getUser,
loading,
anyOtherPropYouPassIn
} = this.props;
const { loading } = this.props;
if (loading) return <Spinner />
return (
ReactDom.createPortal(children, this.el)
)
}

Page doesn't load on redirect reactjs + redux

I am trying to redirect a user after login to home page, the redirect happens (this I know because the url changes and I go to a new page), but the content of the page doesn't load. I keep on getting this error
Warning: You tried to redirect to the same route you're currently on: "/index"
Here's my code for Login.js:
import React, { Component } from 'react';
import '../App.css';
import 'whatwg-fetch';
import { connect } from 'react-redux';
import { loginUser } from './../store/actions/loginActions';
import { Redirect, withRouter } from 'react-router-dom';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
Email: '', Password: '', isloggedin: false
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
this.props.loginUser(this.state)
}
render() {
const { authError, token } = this.props;
if(token) return <Redirect to="/index" /> // I'm telling it to redirect if the state has a token
return (
<div className="Background">
<Card
title="Login"
style={{ width: 400 }}
>
<Form onSubmit={this.handleSubmit} className="login-form">
<Form.Item>
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} name="Email" type="text" onChange={this.handleChange} />
</Form.Item>
<Form.Item>
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" name="Password" onChange={this.handleChange} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" disable='notloggedin' className="login-form-button">
Log in
</Button>
</Form.Item>
</Form>
<div>
{ authError ? <p> { authError } </p> : null }
</div>
</Card>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
authError: state.auth.authError,
token: state.auth.token
}
}
const mapDispatchToProps = (dispatch) => {
return {
loginUser: (data) => dispatch(loginUser(data))
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps) (Login));
My action is:
export const loginUser = (data) => {
return (dispatch, getState) => {
fetch(url, {
credentials: 'include',
method: 'POST',
headers: headers,
body: JSON.stringify(data)})
.then(res => { if (res.ok) {
return res.json() }
else {
return Promise.reject({
status: res.status,
statusText: res.statusText
})
}
})
.then(function(response) {
dispatch({type: 'LOGIN_USER', value: response.AccessToken });
})
.catch((err) => {
dispatch({type: 'LOGIN_USER_FAILED', err });
})
}
};
and my App.js is
import React, { Component } from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import './App.css';
import Login from './components/Login';
import Home from './components/Home';
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h3 className="App-logo"> App Load </h3>
</header>
<BrowserRouter>
<Switch>
<Route path="/" component={Login} />
<Route path="/index" component={Home} />
</Switch>
</BrowserRouter>
);}}
export default App;
Could anyone please let me know if they see any reason as to why the redirect is working but not loading the page components? I'll really appreciate any pointers.
try to wrap you whole App component into BrowserRouter
I shifted this <Route path="/" component={Login} /> to the bottom of my routes in App.js and it worked.

React App Login Error : Maximum update depth exceeded

I am using react with redux to build login authentication system with backend passport jwt .
login works fine before , i have added PrivateRoute to some Routes that requires authentication.
Errors i got :
src/actions/authActions.js
import { GET_ERRORS,CLEAR_ERRORS,SET_CURRENT_USER,LOGOUT_USER} from './types';
import axios from 'axios';
import setAuthToken from '../utils/setAuthToken';
import jwt_decode from 'jwt-decode';
export const loginUser= userdata =>dispatch=>{
axios.post('/api/auth/login',userdata)
.then(res=>{
console.log('loginUser action response ==>',res.data);
const {token}=res.data;
localStorage.setItem('jwtToken',token);
setAuthToken(token);
// Decode token to get user data
const decoded = jwt_decode(token);
dispatch(setCurrentUser(decoded));
}).catch(err=>{
dispatch({type:GET_ERRORS,payload:err.response.data});
})
}
// Set logged in user
export const setCurrentUser = decoded => {
return {
type: SET_CURRENT_USER,
payload: decoded
};
};
src/reducers/authReducers.js
import isEmpty from '../validation/is-empty';
import { SET_CURRENT_USER,LOGIN_USER,LOGOUT_USER} from '../actions/types';
const initialState = {
isAuthenticated: false,
user: {}
};
export default function(state = initialState, action) {
switch (action.type) {
case LOGIN_USER:
case SET_CURRENT_USER:
return {
...state,
isAuthenticated: !isEmpty(action.payload),
user: action.payload
};
case LOGOUT_USER:
return {
...state,
isAuthenticated:false,
user: {}
};
default:
return state;
}
}
App.js
import React, { Component } from 'react';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import {Provider} from 'react-redux';
import store from './store';
import Footer from './partials/footer';
import Header from './partials/header';
import Login from './components/auth/login';
import { setCurrentUser ,logoutUser} from './actions/authActions';
import jwt_decode from 'jwt-decode';
import setAuthToken from './utils/setAuthToken';
import PrivateRoute from './utils/PrivateRoute';
import Dashboard from './components/user/dashboard';
import NotFound404 from './components/error/404';
if(localStorage.jwtToken){
setAuthToken(localStorage.jwtToken);
// Decode token and get user info and exp
const decoded = jwt_decode(localStorage.jwtToken);
store.dispatch(setCurrentUser(decoded));
// Check for expired token
const currentTime = Date.now() / 1000;
if (decoded.exp < currentTime) {
// Logout user
store.dispatch(logoutUser());
// Clear current Profile
//store.dispatch(clearCurrentProfile());
// Redirect to login
window.location.href = '/login';
}
}
export default class App extends Component {
constructor(){
super();
this.state={
isAuthenticated:store.getState().auth.isAuthenticated
}
}
render() {
return (
<Provider store={store}>
<Router>
<div className="App">
<Header/>
<div className="container">
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/login" component={Login} />
<PrivateRoute isAuthenticated={this.state.isAuthenticated} exact path="/dashboard" component={Dashboard}/>
<Route component={NotFound404} />
</Switch>
</div>
<Footer/>
</div>
</Router>
</Provider>
);
}
}
src/components/login.js
import React, { Component } from 'react'
import { Link } from 'react-router-dom';
import classnames from 'classnames';
import { connect } from 'react-redux';
import { loginUser } from '../../actions/authActions';
import { PropTypes } from 'prop-types';
class Login extends Component {
constructor(){
super();
this.state={
email:'',
password:'',
errors:{}
}
this.handleChange=this.handleChange.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
handleChange(event){
this.setState({
[event.target.name]:event.target.value
});
}
handleSubmit(event){
event.preventDefault();
const user={
email:this.state.email,
password:this.state.password
}
this.props.loginUser(user);
}
componentDidMount() {
if (this.props.auth.isAuthenticated) {
this.props.history.push('/dashboard');
}
}
componentWillReceiveProps(nextProps){
if(nextProps.errors){
this.setState({
errors:nextProps.errors
});
}
if(nextProps.auth.isAuthenticated){
this.props.history.push('/dashboard');
}
}
render () {
const {errors} = this.state;
return (
<div className="row my-5">
<div className="col-md-4 offset-md-4 col-sm-12">
<div className="card shadow-sm">
<h5 className="card-header">Login</h5>
<div className="card-body">
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="email" className="label">Email</label>
<input type="email" id="email" name="email" value={this.state.email} onChange={this.handleChange} className={classnames('form-control',{'is-invalid':errors.email})}/>
{errors.email && (<div className="invalid-feedback">{errors.email}</div>)}
</div>
<div className="form-group">
<label htmlFor="password" className="label">Password</label>
<input type="password" id="password" name="password" value={this.state.password} onChange={this.handleChange} className={classnames('form-control',{'is-invalid':errors.password})}/>
{errors.password && (<div className="invalid-feedback">{errors.password}</div>)}
</div>
<button type="submit" className="btn btn-success btn-block">Login</button>
</form>
<div className="py-3 border-bottom"></div>
<Link to="/register" className="btn btn-default btn-block my-2">Haven't created account yet ?</Link>
<Link to="/forgotpassword" className="btn btn-default btn-block">Forgot Password ?</Link>
</div>
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state, ownProps) => ({
auth:state.auth,
errors:state.errors
})
const mapDispatchToProps = {
loginUser
}
Login.propTypes={
auth:PropTypes.object.isRequired,
errors:PropTypes.object.isRequired,
loginUser:PropTypes.func.isRequired
}
export default connect(mapStateToProps,mapDispatchToProps)(Login)
PrivateRoute.js component
import React from 'react';
import {Route,Redirect} from 'react-router-dom';
const PrivateRoute=({component: Component, isAuthenticated, ...rest}) => {
return (
<Route
{...rest}
render={(props) => isAuthenticated === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
/>
)
}
export default PrivateRoute;
Please help me to solve this error .
I have solved my error by replacing PrivateRoute component as below :
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
const PrivateRoute = ({ component: Component,auth, ...rest }) => (
<Route
{...rest}
render={props =>
auth.isAuthenticated === true ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
PrivateRoute.propTypes = {
auth: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
auth: state.auth
});
export default connect(mapStateToProps)(PrivateRoute);
I suggest you use another state variable for saving request status. like loggingIn if it's true, show loading if it's false and isAuthenticated is false, the user is not requested for login and it's not logged in. so redirect it to /login.
PrivateRoute.js component
import React from 'react';
import {Route,Redirect} from 'react-router-dom';
class PrivateRoute extends Component {
render() {
const {
component: Component, loggingIn, isAuthenticated, ...rest
} = this.props;
if (loggingIn) {
return (
<div>
Please wait.
</div>
);
}
return (<Route {...rest} render={props => (isAuthenticated ? (<Component {...props} />) : (<Redirect to={{ pathname: '/login', state: { from: props.location } }} />))} />);
}}
export default PrivateRoute;
src/actions/authActions.js
import { GET_ERRORS,CLEAR_ERRORS,SET_CURRENT_USER,LOGOUT_USER} from './types';
import axios from 'axios';
import setAuthToken from '../utils/setAuthToken';
import jwt_decode from 'jwt-decode';
export const loginUser= userdata =>dispatch=>{
dispatch(loggingIn(true));
axios.post('/api/auth/login',userdata)
.then(res=>{
dispatch(loggingIn(false));
console.log('loginUser action response ==>',res.data);
const {token}=res.data;
localStorage.setItem('jwtToken',token);
setAuthToken(token);
// Decode token to get user data
const decoded = jwt_decode(token);
dispatch(setCurrentUser(decoded));
}).catch(err=>{
dispatch(loggingIn(false));
dispatch({type:GET_ERRORS,payload:err.response.data});
})
}
// Set logged in user
export const setCurrentUser = decoded => {
return {
type: SET_CURRENT_USER,
payload: decoded
};
};
export const loggingIn = status => {
return {
type: 'LOGGINGIN',
status,
}
}
src/reducers/authReducers.js
import isEmpty from '../validation/is-empty';
import { SET_CURRENT_USER,LOGIN_USER,LOGOUT_USER} from '../actions/types';
const initialState = {
isAuthenticated: false,
user: {}
};
export default function(state = initialState, action) {
switch (action.type) {
case LOGIN_USER:
case SET_CURRENT_USER:
return {
...state,
isAuthenticated: !isEmpty(action.payload),
user: action.payload
};
case LOGOUT_USER:
return {
...state,
isAuthenticated:false,
user: {}
};
case 'LOGGINGIN':
return {
...state,
loggingIn: action.status,
};
default:
return state;
}
}
and remember pass loggingIn as props to privateRoute
Edit : show how to use in App.js
App.js
import React, { Component } from 'react';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import {connect} from 'react-redux';
import Footer from './partials/footer';
import Header from './partials/header';
import Login from './components/auth/login';
import { setCurrentUser ,logoutUser} from './actions/authActions';
import jwt_decode from 'jwt-decode';
import setAuthToken from './utils/setAuthToken';
import PrivateRoute from './utils/PrivateRoute';
import Dashboard from './components/user/dashboard';
import NotFound404 from './components/error/404';
class App extends Component {
constructor(props){
super(props);
const { dispatch } = props;
if(localStorage.jwtToken){
setAuthToken(localStorage.jwtToken);
// Decode token and get user info and exp
const decoded = jwt_decode(localStorage.jwtToken);
dispatch(setCurrentUser(decoded));
// Check for expired token
const currentTime = Date.now() / 1000;
if (decoded.exp < currentTime) {
// Logout user
dispatch(logoutUser());
// Clear current Profile
//dispatch(clearCurrentProfile());
// Redirect to login
window.location.href = '/login';
}
}
}
render() {
const { isAuthenticated, loggingIn } = this.props;
return (
<Provider store={store}>
<Router>
<div className="App">
<Header/>
<div className="container">
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/login" component={Login} />
<PrivateRoute loggingIn={loggingIn} isAuthenticated={isAuthenticated} exact path="/dashboard" component={Dashboard}/>
<Route component={NotFound404} />
</Switch>
</div>
<Footer/>
</div>
</Router>
</Provider>
);
}
}
const mapStateToProps = state = {
const { loggingIn, isAuthenticated } = state.auth;
return { loggingIn, isAuthenticated }
}
export default connect(mapStateToProps)(App);

Resources