I have the following setup:
App.js
import AppContext from './context/AppContext.js';
import router from './routes/routes.js';
function App() {
const [token, setToken] = useState("");
function login(token) {
setToken(token);
}
return (
<React.StrictMode>
<AppContext.Provider value={{ token, login }}>
<RouterProvider router={router} />
</AppContext.Provider>
</React.StrictMode>
);
}
export default App;
routes.js
export default createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{
path: "home",
element: <Home />
},
{
path: "admin",
element: <ProtectedRoute element={Admin} />
},
{
path: "login",
element: <Login />
}
]
}
]);
ProtectedRoute.js
export default function ProtectedRoute({ element: Component, ...rest }) {
const ctx = useContext(AppContext);
return (
ctx.token !== "" ? <Component /> : <Navigate to="/login" />
);
}
I want to be able check if the user is logged in by accessing information from a context, however the returned object always contains the default values. Is there a way to access context information with createBrowserRouter
in this scenario?
The protected route component should be refactored to be rendered as a layout route component by rendering an Outlet
instead of some passed prop.
import { Navigate, Outlet } from 'react-router-dom';
export default function ProtectedRoute() {
const { token } = useContext(AppContext);
return token
? <Outlet />
: <Navigate to="/login" replace />;
}
export default createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{ path: "home", element: <Home /> },
{
element: <ProtectedRoute />,
children: [
{
path: "admin",
element: <Admin />
},
// ... other protected routes
],
},
{ path: "login", element: <Login /> }
// ... other unprotected routes
]
}
]);