Me di cuenta de que cuando actualizaba la página de mi aplicación, iría a la página de inicio de sesión y luego iría al tablero si estaba autenticado. Independientemente de la página en la que actualicé.

Soy bastante nuevo para reaccionar, pero creo que el problema está en mi lógica PrivateRoute.js. Va «else: redirige para iniciar sesión» pero no falla en la página de inicio de sesión, por lo que sigue la ruta «si se redirige autenticado al tablero».

App.js:

import React, { Component, Fragment } from "react"; import ReactDOM from "react-dom"; import { HashRouter as Router, Route, Switch, Redirect } from "react-router-dom"; import { Provider as AlertProvider } from "react-alert"; import AlertTemplate from "react-alert-template-basic"; import Header from "./layout/Header"; import Sidebar from "./layout/Sidebar"; import Home from "./common/Home"; import Profile from "./accounts/profile"; import Dashboard from "./leads/Dashboard"; import Alerts from "./layout/Alerts"; import Login from "./accounts/Login"; import Register from "./accounts/Register"; import PrivateRoute from "./common/PrivateRoute"; import { Provider } from "react-redux"; import store from "../store"; import { loadUser } from "../actions/auth"; // Alert Options const alertOptions = { timeout: 3000, position: "top center" }; class App extends Component { componentDidMount() { store.dispatch(loadUser()); } render() { return ( {amp}lt;Provider store={store}{amp}gt; {amp}lt;AlertProvider template={AlertTemplate} {...alertOptions}{amp}gt; {amp}lt;Router{amp}gt; {amp}lt;Fragment{amp}gt; {amp}lt;Header /{amp}gt; {amp}lt;Alerts /{amp}gt; {amp}lt;div className="container-fluid page-body-wrapper"{amp}gt; {amp}lt;Sidebar /{amp}gt; {amp}lt;Switch{amp}gt; {amp}lt;Route exact path="/" component={Home} /{amp}gt; {amp}lt;PrivateRoute exact path="/dashboard" component={Dashboard} /{amp}gt; {amp}lt;PrivateRoute exact path="/profile" component={Profile} /{amp}gt; {amp}lt;Route exact path="/login" component={Login} /{amp}gt; {amp}lt;Route exact path="/register" component={Register} /{amp}gt; {amp}lt;/Switch{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;/Fragment{amp}gt; {amp}lt;/Router{amp}gt; {amp}lt;/AlertProvider{amp}gt; {amp}lt;/Provider{amp}gt; ); } } ReactDOM.render({amp}lt;App /{amp}gt;, document.getElementById("app")); 

PrivateRoute.js

 import React from "react"; import { Route, Redirect } from "react-router-dom"; import { connect } from "react-redux"; import PropType from "prop-types"; const PrivateRoute = ({ component: Component, auth, path, ...rest }) ={amp}gt; ( {amp}lt;Route path={path} {...rest} render={props ={amp}gt; { if (auth.isLoading) { return {amp}lt;h2{amp}gt;Loading...{amp}lt;/h2{amp}gt;; } else if (auth.isAuthenticated) { return {amp}lt;Component {...props} /{amp}gt;; } else { return {amp}lt;Redirect to="/login" /{amp}gt;; } }} /{amp}gt; ); const mapStateToProps = state ={amp}gt; ({ auth: state.auth }); export default connect(mapStateToProps)(PrivateRoute); 

Login.js

 import React, { Component } from "react"; import { Link, Redirect } from "react-router-dom"; import { connect } from "react-redux"; import PropTypes from "prop-types"; import { login } from "../../actions/auth"; export class Login extends Component { state = { username: "", password: "" }; static propTypes = { login: PropTypes.func.isRequired, isAuthenticated: PropTypes.bool }; onSubmit = e ={amp}gt; { e.preventDefault(); this.props.login(this.state.username, this.state.password); }; onChange = e ={amp}gt; this.setState({ [e.target.name]: e.target.value }); render() { { /*if (this.props.isAuthenticated) { return {amp}lt;Redirect to="/dashboard" /{amp}gt;; }*/ } const { username, password } = this.state; return ( {amp}lt;div className="col-md-12 m-auto" style={{ maxWidth: 500 }}{amp}gt; {amp}lt;div className="card card-body mt-5"{amp}gt; {amp}lt;h2 className="text-center py-3"{amp}gt;Login to Reely.io{amp}lt;/h2{amp}gt; {amp}lt;form onSubmit={this.onSubmit}{amp}gt; {amp}lt;div className="form-group"{amp}gt; {amp}lt;label{amp}gt;Username{amp}lt;/label{amp}gt; {amp}lt;input type="text" className="form-control" name="username" onChange={this.onChange} value={username} /{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;div className="form-group"{amp}gt; {amp}lt;label{amp}gt;Password{amp}lt;/label{amp}gt; {amp}lt;input type="password" className="form-control" name="password" onChange={this.onChange} value={password} /{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;div className="form-group"{amp}gt; {amp}lt;button type="submit" className="btn btn-primary"{amp}gt; Login {amp}lt;/button{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;p{amp}gt; Need an account? {amp}lt;Link to="/register"{amp}gt;Register{amp}lt;/Link{amp}gt; {amp}lt;/p{amp}gt; {amp}lt;/form{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;/div{amp}gt; ); } } const mapStateToProps = state ={amp}gt; ({ isAuthenticated: state.auth.isAuthenticated }); export default connect(mapStateToProps, { login })(Login); 

auth.js — acciones

 import axios from "axios"; import { returnErrors } from "./messages"; import { USER_LOADED, USER_LOADING, AUTH_ERROR, LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT_SUCCESS, REGISTER_SUCCESS, REGISTER_FAIL } from "./types"; // CHECK TOKEN {amp}amp; LOAD USER export const loadUser = () ={amp}gt; (dispatch, getState) ={amp}gt; { // User Loading dispatch({ type: USER_LOADING }); axios .get("/api/auth/user", tokenConfig(getState)) .then(res ={amp}gt; { dispatch({ type: USER_LOADED, payload: res.data }); }) .catch(err ={amp}gt; { dispatch(returnErrors(err.response.data, err.response.status)); dispatch({ type: AUTH_ERROR }); }); }; // LOGIN USER export const login = (username, password) ={amp}gt; dispatch ={amp}gt; { // Headers const config = { headers: { "Content-Type": "application/json" } }; // Request Body const body = JSON.stringify({ username, password }); axios .post("/api/auth/login/", body, config) .then(res ={amp}gt; { dispatch({ type: LOGIN_SUCCESS, payload: res.data }); }) .catch(err ={amp}gt; { dispatch(returnErrors(err.response.data, err.response.status)); dispatch({ type: LOGIN_FAIL }); }); }; // REGISTER USER export const register = ({ username, password, email }) ={amp}gt; dispatch ={amp}gt; { // Headers const config = { headers: { "Content-Type": "application/json" } }; // Request Body const body = JSON.stringify({ username, password, email }); axios .post("/api/auth/register/", body, config) .then(res ={amp}gt; { dispatch({ type: REGISTER_SUCCESS, payload: res.data }); }) .catch(err ={amp}gt; { dispatch(returnErrors(err.response.data, err.response.status)); dispatch({ type: REGISTER_FAIL }); }); }; // LOGOUT USER export const logout = () ={amp}gt; (dispatch, getState) ={amp}gt; { axios .post("/api/auth/logout/", null, tokenConfig(getState)) .then(res ={amp}gt; { dispatch({ type: LOGOUT_SUCCESS }); }) .catch(err ={amp}gt; { dispatch(returnErrors(err.response.data, err.response.status)); }); }; // SETUP CONFIG W/ TOKEN - Helper Function export const tokenConfig = getState ={amp}gt; { // Get token from state const token = getState().auth.token; // Headers const config = { headers: { "Content-Type": "application/json" } }; // If token, add to header config if (token) { config.headers["Authorization"] = `Token ${token}`; } return config; }; 

tipos.js

 export const GET_LEADS = "GET_LEADS"; export const DELETE_LEADS = "DELETE_LEADS"; export const ADD_LEAD = "ADD_LEAD"; export const GET_ERRORS = "GET_ERRORS"; export const CREATE_MESSAGE = "CREATE_MESSAGE"; export const USER_LOADING = "USER_LOADING"; export const USER_LOADED = "USER_LOADED"; export const AUTH_ERROR = "AUTH_ERROR"; export const LOGIN_SUCCESS = "LOGIN_SUCCESS"; export const LOGIN_FAIL = "LOGIN_FAIL"; export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS"; export const REGISTER_SUCCESS = "REGISTER_SUCCESS"; export const REGISTER_FAIL = "REGISTER_FAIL"; 

auth.js — reductor

 import { USER_LOADED, USER_LOADING, AUTH_ERROR, LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT_SUCCESS, REGISTER_SUCCESS, REGISTER_FAIL } from "../actions/types"; const initialState = { token: localStorage.getItem("token"), isAuthenticated: null, isLoading: false, user: null }; export default function(state = initialState, action) { switch (action.type) { case USER_LOADING: return { ...state, isLoading: true }; case USER_LOADED: return { ...state, isAuthenticated: true, isLoading: false, user: action.payload }; case LOGIN_SUCCESS: case REGISTER_SUCCESS: localStorage.setItem("token", action.payload.token); return { ...state, ...action.payload, isAuthenticated: true, isLoading: false }; case AUTH_ERROR: case LOGIN_FAIL: case LOGOUT_SUCCESS: case REGISTER_FAIL: localStorage.removeItem("token"); return { ...state, token: null, user: null, isAuthenticated: false, isLoading: false }; default: return state; } } 

El problema proviene del estado initialState . isLoading establecer isLoading en true .

 const PrivateRoute = ({ component: Component, auth, path, ...rest }) ={amp}gt; ( {amp}lt;Route path={path} {...rest} render={props ={amp}gt; { if (auth.isLoading) { // If initialState.isLoading = false, // then your application will skip this step // (just after a refresh) return {amp}lt;h2{amp}gt;Loading...{amp}lt;/h2{amp}gt;; } else if (auth.isAuthenticated) { // But because USER_LOADING is not triggered yet, // your are not authenticated ! return {amp}lt;Component {...props} /{amp}gt;; } else { // Then you drop here return {amp}lt;Redirect to="/login" /{amp}gt;; } }} /{amp}gt; ); 

En mi proyecto actual, administré este caso con una variable initialized (que es falsa al principio):

 import React, {FC} from "react" import {RouteProps, Route, Redirect} from "react-router-dom" import {useAuthState} from "./context" const PrivateRoute: FC{amp}lt;RouteProps{amp}gt; = props ={amp}gt; { const auth = useAuthState() if (!auth.initialized) { return null } if (!auth.authenticated) { return {amp}lt;Redirect to="/login" /{amp}gt; } return {amp}lt;Route {...props} /{amp}gt; } export default PrivateRoute