Home > database >  Trying to restrict pages to only users who are logged in but conditional never seems to run
Trying to restrict pages to only users who are logged in but conditional never seems to run

Time:08-27

I'm trying to set up routing in React v18 that restricts certain pages to only users who are logged in. I can't seem to get the function in the return statement to work. Login and Register work OK. If I put another component outside the function, the same level as Login and Register, it works fine, too. But when the page loads, it should got to localhost/, see there's no token, then route to /login. Right now it just stays on localhost/ and shows an empty page. The warning in the console says "No routes match location '/' ". That is true, because the component with path "/" is in AppViews and should be restricted. But it's not moving the user to `/login'. Why not? What am I missing?

export const MyApp = () => {
  const [token, setTokenState] = useState(localStorage.getItem('token'))

  const setToken = (newToken) => {
    localStorage.setItem('token', newToken)
    setTokenState(newToken)
  }


  return (
    <>
        <Routes>
            { <Route render={() => {
                if (localStorage.getItem("app_token")) {
                    return <>
                        <Route>
                            <AppViews />
                        </Route>
                    </>
                } else {
                    return <Navigate to="/login" />
                }
                }} />
             }
            <Route path="/login" element={<Login />} />
            <Route path="/register" element={<Register />} />         
        </Routes>
    </>
  )
}
 
export default MyApp;

CodePudding user response:

In react-router-dom@6 the Route component hasn't any render prop. In other words, the render prop is completely ignored and has no effect. All the routed content is rendered out on the element prop. Use a ternary operator to conditionally render the redirect or the AppViews component.

export const MyApp = () => {
  const [token, setTokenState] = useState(localStorage.getItem('token'))

  const setToken = (newToken) => {
    localStorage.setItem('token', newToken)
    setTokenState(newToken)
  }

  return (
    <Routes>
      <Route
        path="/*"
        element={localStorage.getItem("app_token")
          ? <AppViews />
          : <Navigate to="/login" replace />
        }
      />
      <Route path="/login" element={<Login />} />
      <Route path="/register" element={<Register />} />         
    </Routes>
  );
}

It's more conventional to create a protected route component.

Example:

import { Navigate, Outlet } from 'react-router-dom';

const ProtectedRoute = () => {
  const appToken = localStorage.getItem("app_token");

  return appToken
    ? <Outlet />
    : <Navigate to="/login" replace />
};

...

export const MyApp = () => {
  const [token, setTokenState] = useState(localStorage.getItem('token'))

  const setToken = (newToken) => {
    localStorage.setItem('token', newToken)
    setTokenState(newToken)
  }

  return (
    <Routes>
      <Route element={<ProtectedRoute />}>
        <Route path="/*" element={<AppViews />} />
      </Route>
      <Route path="/login" element={<Login />} />
      <Route path="/register" element={<Register />} />         
    </Routes>
  );
}
  • Related