I'm currently creating private routes using react-router
6 and Outlet
. I have a simple setup as follows:
Routes in App.js
return (
<BrowserRouter>
<div className="App">
<Routes>
<Route path="/" element={<Login />}></Route>
<Route path="/register" element={<Register />}></Route>
<Route element={<PrivateRoutes />}>
<Route path="/dashboard" element={<Dashboard />}></Route>
<Route path="/reports" element={<Reports />}></Route>
<Route path="/settings" element={<Settings />}></Route>
</Route>
</Routes>
</div>
</BrowserRouter>
);
PrivateRoutes component
const PrivateRoutes = () => {
console.log("Private Routes was run");
validToken = true;
return (
(checkToken()) ? <Outlet/> : <Navigate to="/" />
);
}
What I noticed though is the PrivateRoutes
component does not run when navigating between any of the private routes, only when first entering one of the PrivateRoutes
.
For example, I want the PrivateRoutes
component to run when I navigate between the /dashboard
and /reports
routes using my primary nav.
I tried using both Link
and useNavigate
imports from react-router-dom
, but neither re-triggers the PrivateRoutes
component.
<div id='nav-links' className='flex flex-row'>
<div onClick={() => navigate('/dashboard')}>Dashboard</div>
<div onClick={() => navigate('/reports')}>Reports</div>
<div onClick={() => navigate('/settings')}>Settings</div>
</div>
and
<div id='nav-links' className='flex flex-row'>
<Link to='/dashboard'>Dashboard</Link>
<Link to='/reports'>Reports</div>
<Link to='/settings'>Settings</div>
</div>
What am I missing or not understanding? Is there a simple syntax adjustment one can use so PrivateRoutes
is always run upon navigation?
CodePudding user response:
Your routes are fine. You will want to couple the checkToken
to the route change. You can listen to route changes using the useLocation
and useEffect
hooks. I'm assuming checkToken
is synchronous.
Example:
const PrivateRoutes = () => {
const { pathname } = useLocation();
const [isValidToken, setIsValidToken] = useState(); // <-- initially undefined
useEffect(() => {
// initial mount or route changed, check token
setIsValidToken(!!checkToken());
}, [pathname]);
if (isValidToken === undefined) {
return null; // or loading indicator/spinner/etc
}
return isValidToken ? <Outlet/> : <Navigate to="/" replace />;
}
CodePudding user response:
Change your code from this,
<Route element={<PrivateRoutes />}>
<Route path="/dashboard" element={<Dashboard />}></Route>
<Route path="/reports" element={<Reports />}></Route>
<Route path="/settings" element={<Settings />}></Route>
</Route>
to this
<Route path="/privateRoute" element={<PrivateRoutes />}>
<Route path="dashboard" element={<Dashboard />}></Route>
<Route path="reports" element={<Reports />}></Route>
<Route path="settings" element={<Settings />}></Route>
</Route>
and accordingly make changes in your nav