Home > Mobile >  React: Private Routes Using Outlet & Router V6
React: Private Routes Using Outlet & Router V6

Time:08-07

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

  • Related