Here it’s shown the most basic implementation of authentication in React-Router v6. loggedIn
flag in PrivateRoutes
does not change when updated to true after updating context, and so the private routes cannot be accessed when navigating to them. Why is that?
import './App.css';
import {
BrowserRouter,
Navigate,
Outlet,
Route,
Routes,
useNavigate
} from 'react-router-dom';
import React, { useState } from 'react';
function App() {
return (
<div>
<AuthProvider>
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route element={<PrivateRoutes />}>
<Route path="/secret" element={<SecretPage />} />
{/** ... Other protected pages ...*/}
</Route>
</Routes>
</BrowserRouter>
</AuthProvider>
</div>
);
}
function PrivateRoutes() {
const { loggedIn } = useAuth();
return loggedIn ? <Outlet />: <Navigate to="/" />
}
function HomePage() {
const navigate = useNavigate();
return <>
<h1>Home page</h1>
<button onClick={() => navigate('/secret')}>
Go to secret page
</button>
</>
}
function SecretPage() {
return <>
<h1>Secret Page</h1>
</>
}
const AuthContext = React.createContext()
const AuthProvider = ({ children }) => {
const { loggedIn, signIn } = useAuth()
return
<AuthContext.Provider value={loggedIn}>
{/**
* Button to trigger sign in and showing the
* current status.
*/}
<button onClick={signIn}>LogIn</button>
<h2>Logged In: {loggedIn.toString()}</h2>
<p>-----------------------</p>
{children}
</AuthContext.Provider>
}
const useAuth = () => {
const [loggedIn, setLoggedIn] = useState(false)
const signIn = () => {
{/** sign in logic ....*/}
setLoggedIn(true);
};
return { loggedIn, signIn };
}
export default App;
2
Answers
useAuth
is a React hook and React hooks don’t share internal state. Each instance ofuseAuth
has its own independentloggedIn
state.Refactor the
AuthProvider
to hold theloggedIn
state and update theuseAuth
hook to consume the provided context value. This is how all instances ofuseAuth
get the same value.try this