Search code examples
javascriptreactjshttp-redirectreact-routerreact-router-dom

React - redirect to login page when not authenticated


This is my primary react file:

// App.tsx
const App: FC = () => {

  const isLoggedIn: boolean = localStorage.getItem('logged_user') !== null;

  return (
    <BrowserRouter>
        <Routes>
          <Route path="/main" element={isLoggedIn ? <Main/> : <Navigate to='/login'/>}/>
          <Route path="/about" element={isLoggedIn ? <About/> : <Navigate to='/login'/>}/>
          <Route path="/login" element={<Login/>}/>
        </Routes>
    </BrowserRouter>
  );
}

export default App;

After logging in, I store the user in local storage.

I want to achieve the behaviour of redirections to the /login page when the user is not authenticated (when it is not stored in localstorage).

Generally, the above approach works but only sometimes. Sometimes, when I go to '/main', I would get redirected to '/login' even though I was logged in. I assume this is caused by React's nature of re-renders.

How can I approach this?


Solution

  • I'm guessing the redirect to "/login" works the first time, you log in, then try to navigate to "/main" or "/about" and are getting redirected back to "/login" until you do something like a page reload and read any persisted "logged_user" state and then get stuck not being to log out and get redirected back to "/login".

    You should store the isLoggedIn value in local state, initialized from localStorage, and provide a way within the app to toggle the state. Use an useEffect hook to persist local state changes back to localStorage.

    Example:

    const App: FC = () => {
      const [isLoggedIn, setIsLoggedIn] = useState<boolean>(
        () => localStorage.getItem('logged_user') !== null
      );
    
      useEffect(() => {
        localStorage.setItem('logged_user', JSON.stringify(isLoggedIn));
      }, [isLoggedIn]);
    
      
      const logIn = () => setIsLoggedIn(true);
    
      // pass this callback to components you want to allow logging out
      // it will update the local state and then get persisted
      const logOut = () => setIsLoggedIn(false);
    
      return (
        <BrowserRouter>
          <Routes>
            <Route path="/main" element={isLoggedIn ? <Main/> : <Navigate to='/login'/>}/>
            <Route path="/about" element={isLoggedIn ? <About/> : <Navigate to='/login'/>}/>
            <Route path="/login" element={<Login onLogIn={logIn} />}/>
          </Routes>
        </BrowserRouter>
      );
    }