title: react - react router - privateRoute - infinite loop
body: <p>I'm trying to make a simple authentication system in my Single Page Application.
  I want to disable all routes execpt <code>/login</code> for guest.
  The way to know if the user is authenticated or a guest it's to know if there are an <code>access_token</code> in the <code>localStorage</code>.</p>
  
  <p>When I'm starting the app the <code>Main</code> component is started. The component define the routes and know if the user is authenticated by check the <code>localStorage</code>.</p>
  
  <p>The default route (<code>/</code>) is for render the <code>Home</code> component but, like this <a href="https://reacttraining.com/react-router/web/example/auth-workflow" rel="nofollow noreferrer" title="example">example</a> of <strong>react router</strong> the <code>Home</code> component is protected by a <code>PrivateRoute</code> object.</p>
  
  <p>The <code>PrivateRoute</code> object check if the user is authenticated. If yes, <code>Home</code> component is rendered, else the user is redirected to the <code>login</code>component at <code>/login</code>.</p>
  
  <p>The <code>Login</code> component redirect the user to <code>/</code> in case of success and execute a callback to give the <code>access_token</code>.</p>
  
  <p>The <code>Main</code> component define the callback, It's about to save the <code>access_token</code> in the <code>localStorage</code> and change the <code>state</code> for declare the user as authenticated. And now, the user can access the <code>Home</code> component.</p>
  
  <p>My problem is, the <code>PrivateRoute</code> system always the check the user as a guest so it's always a redirection to <code>/login</code>. But when the are an <code>access_token</code> in <code>localStorage</code> the <code>Login</code> component redirect to the <code>Home</code> protected by the <code>PrivateRoute</code> and this is an infite loop despite the <code>handleLogin</code> callback.</p>
  
  <p>Can you find a solution ?</p>
  
  <hr>
  
  <p><strong>Main.jsx</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>import React, {Component} from 'react';
  import ReactDOM from 'react-dom';
  import {BrowserRouter, Link, Redirect, Route} from "react-router-dom";
  import {Login} from "./Login"
  import {Home} from "./Home";
  
  
  class Main extends Component {
      constructor(props) {
          super(props);
  
          this.handleLogout = this.handleLogout.bind(this);
          this.handleLogin = this.handleLogin.bind(this);
          this.state = {authed: localStorage.getItem('access_token') !== null};
      }
  
      componentDidCatch(error, info) {
      }
  
      handleLogout(event) {
          event.preventDefault();
          localStorage.removeItem('access_token');
          this.setState({authed: false});
      }
  
      handleLogin(token) {
          localStorage.setItem('access_token', token);
          this.setState({authed: token !== null});
      }
  
      render() {
          const PrivateRoute = ({component: Component, ...rest}) =&gt; (
              &lt;Route {...rest} render={props =&gt;
                  this.state.authed()
                      ? (&lt;Component {...props} /&gt;)
                      : (&lt;Redirect to="/login"/&gt;)
              }
              /&gt;
          );
  
          const LoginLogout = () =&gt; {
              return this.state.authed
                  ? (&lt;button onClick={this.handleLogout}&gt;Logout&lt;/button&gt;)
                  : (&lt;Link to="/login"&gt;Login&lt;/Link&gt;);
          };
  
          return (
              &lt;BrowserRouter&gt;
                  &lt;div&gt;
                      &lt;ul&gt;
                          &lt;li&gt;
                              &lt;Link to="/"&gt;Home&lt;/Link&gt;
                          &lt;/li&gt;
                          &lt;li&gt;
                              &lt;LoginLogout/&gt;
                          &lt;/li&gt;
                      &lt;/ul&gt;
  
                      &lt;Route path="/login" component={() =&gt; &lt;Login handleLogin={this.handleLogin}/&gt;}/&gt;
                      &lt;PrivateRoute exact path="/" component={Home}/&gt;
  
                  &lt;/div&gt;
              &lt;/BrowserRouter&gt;
          );
      }
  }
  
  if (document.getElementById('main')) {
      ReactDOM.render(&lt;Main/&gt;, document.getElementById('main'));
  }
  </code></pre>
  
  <p><strong>Login.jsx</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>import React, {Component} from 'react';
  import {Redirect} from "react-router-dom";
  
  export class Login extends Component {
  
      constructor(props) {
          super(props);
  
          this.state = {
              email: '',
              password: '',
              redirect: localStorage.getItem('access_token') !== null,
              token: null,
              loading: false,
              error: null
          };
          this.handleInputChange = this.handleInputChange.bind(this);
          this.handleSubmit = this.handleSubmit.bind(this);
      }
  
      componentWillUnmount() {
          this.props.handleLogin(this.state.token);
      }
  
      handleInputChange(event) {
          const target = event.target;
          const value = target.type === 'checkbox' ? target.checked : target.value;
          const name = target.name;
  
          this.setState({
              [name]: value
          });
      }
  
      handleSubmit(event) {
          event.preventDefault();
          this.setState({
              error: null,
              loading: true
          });
          axios.post('/api/login', {
              'client_id': '3',
              'email': this.state.email,
              'password': this.state.password,
              'confirm_password': this.state.password
          }).then((response) =&gt; {
              let token = response.data.access_token;
              this.setState({
                  redirect: true,
                  token: token,
                  loading: false
              });
          }, (error) =&gt; {
              console.error('error', error.response.data);
              this.setState({
                  error: error.response.data,
                  loading: false
              });
          });
      }
  
      render() {
  
          if (this.state.redirect)
              return (&lt;Redirect to={"/"}/&gt;);
  
          return (
              &lt;form onSubmit={this.handleSubmit}&gt;
                  &lt;label htmlFor="email"&gt;Email :&lt;/label&gt;
                  &lt;input type="text" name="email" id="email" value={this.state.email} onChange={this.handleInputChange}
                         disabled={this.state.loading}/&gt;
                  &lt;label htmlFor="password"&gt;Password :&lt;/label&gt;
                  &lt;input type="password" name="password" id="password" value={this.state.password}
                         onChange={this.handleInputChange} disabled={this.state.loading}/&gt;
                  &lt;button type="submit"
                          disabled={this.state.loading}&gt;{this.state.loading ? "..." : "Se connecter"}&lt;/button&gt;
                  {this.state.error &amp;&amp; (
                      &lt;div&gt;
                          &lt;p&gt;Erreur : {JSON.stringify(this.state.error)}&lt;/p&gt;
                      &lt;/div&gt;
                  )}
              &lt;/form&gt;
          );
      }
  }
  </code></pre>