Este es mi archivo de reacción principal:
// 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;Después de iniciar sesión, almaceno al usuario en el almacenamiento local.
Quiero lograr el comportamiento de las redirecciones a la página de inicio de sesión cuando el usuario no está autenticado (cuando no está almacenado en el almacenamiento local).
En general, el enfoque anterior funciona, pero solo a veces. A veces, cuando voy a '/main' , me redirigen a '/login' aunque haya iniciado sesión. Supongo que esto se debe a la naturaleza de React de los renderizados.
¿Cómo puedo abordar esto?
La forma en que me gusta hacerlo es crear un <PrivateLink /> , de modo que quede claro que cualquier ruta anidada requiere un usuario autenticado.
const PrivateRoute = (props: { children: React.ReactNode }): JSX.Element => { const { children } = props const isLoggedIn: boolean = localStorage.getItem('logged_user') !== null; const location = useLocation() return isLoggedIn ? ( <>{children}</> ) : ( <Navigate replace={true} to="/login" state={{ from: `${location.pathname}${location.search}` }} /> ) }Luego en tu App.tsx
const App: FC = () => ( <BrowserRouter> <Routes> <Route path="/main" element={<PrivateRoute> <Main/> </PrivateRoute>}/> <Route path="/about" element={<PrivateRoute> <About/> </PrivateRoute>}/> <Route path="/login" element={<Login/>}/> </Routes> </BrowserRouter> ) Como extra adicional, la variable from que se pasa al estado en el <PrivateRoute /> , le permite redirigir al usuario a la página de la que vino después de iniciar sesión.
Supongo que la redirección a "/login" funciona la primera vez, inicias sesión, luego intentas navegar a "/main" o "/about" y te redirigen de nuevo a "/login" hasta que haces algo como un la página vuelve a cargar y lee cualquier estado "logged_user" persistente y luego se atasca sin poder cerrar la sesión y ser redirigido de nuevo a "/ iniciar sesión".
Debe almacenar el valor isLoggedIn en el estado local, inicializado desde localStorage, y proporcionar una forma dentro de la aplicación para alternar el estado. Utilice un useEffect para conservar los cambios de estado local en localStorage.
Ejemplo:
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> ); }