Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

custom hook and private route in React immediately navigates to login

I have a very straight forward private Route in React:

export default function PrivateRoute({ children }) {
  const auth = useAuth();

  return auth ? children : <Navigate to="/login" />;
}

and this is my custom hook:

export default function useAuth() {
  const [loggedIn, setLoggedIn] = useState(false);

  useEffect(() => {
    const token = Cookies.get("token");
    axios
      .get(`${process.env.REACT_APP_API}/auth`, {
        headers: { Authorization: `Bearer ${token}` },
      })
      .then((result) => {
        if (result.status === 200) {
          setLoggedIn(true);
        }
      })
      .catch((error) => console.error(error));
  }, []);

  return loggedIn;
}

The hook successfully returns true or false, but at the time when the PrivateRoute is called, it is false, thus I land on the login page.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

How can I wait for the hook before redirecting to login?

I call the PrivateRoute like this:

<Route
  path="/admin"
  exact
  element={
    <PrivateRoute>
      <Admin />
    </PrivateRoute>
  }
/>
``

>Solution :

The initial loggedIn state value matches the unauthenticated state. Use an indeterminant value that doesn’t match either the confirmed authenticated/unauthenticated status. Check for this indeterminant value and conditionally render null or some loading indicator.

export default function useAuth() {
  const [loggedIn, setLoggedIn] = useState(); // <-- undefined

  useEffect(() => {
    const token = Cookies.get("token");
    axios
      .get(`${process.env.REACT_APP_API}/auth`, {
        headers: { Authorization: `Bearer ${token}` },
      })
      .then((result) => {
        setLoggedIn(result.status === 200);
      })
      .catch((error) => {
        console.error(error)
        setLoggedIn(false);
      });
  }, []);

  return loggedIn;
}

export default function PrivateRoute({ children }) {
  const location = useLocation();
  const auth = useAuth();

  if (auth === undefined) return null; // or loading spinner/etc...

  return auth
    ? children
    : <Navigate to="/login" replace state={{ from: location }} />;
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading