Mayank Yadav
Mayank Yadav

Reputation: 41

Protected Routes in React Router v6, using useState, but always returns false

Here is what I'm trying to do. I get a JWT from google, store it in sessionStorage for the time being, and send it through my API for server-side verification.

This is Protected Route which I'm using to wrap around my protected elements. Like so

 <Route element={<PrivateRouteClient />}>  
                <Route path="/CDashboard" element={<Client_dashboard /> }>
 </Route>




import axios from 'axios';
import React, {useEffect, useState} from 'react';
import {Navigate}  from 'react-router-dom';
import {Outlet}  from 'react-router-dom';

 function PrivateRouteClient() {
  const [isAuth, setIsAuth] = useState(false);
  
  axios.post('http://localhost:8080/something/something', {credential: sessionStorage.getItem("token")})
  .then(function (res){
    console.log(Boolean(res.data["UserAuth"]));
    setIsAuth(Boolean(res.data["UserAuth"]));
    console.log("hi");
    return isAuth;
  })
  console.log(isAuth)
  return isAuth ? <Outlet /> : <Navigate to="/login/Client" />;
}

  
export default PrivateRouteClient

And I cant make the route async cause it will return a promise, and that's not a valid React Component and it throws and error. Can't quite figure out where I'm doing wrong!

Thanks for reading and helping!

Upvotes: 2

Views: 2158

Answers (2)

Mayank Yadav
Mayank Yadav

Reputation: 41

So Drew's answer helped me A LOT, thanks! useEffect is the way to go!

When we run this snippet, the "initial" value of log is "undefined" [this means the type of isAuth is also undefined]. When we run the axios.post, isAuth is set as a string, and not Boolean, so we cant really convert is using the Boolean() method.

 function PrivateRouteClient() {
  const [isAuth, setIsAuth] = useState();
  console.log("initial")
  console.log(isAuth)

  useEffect(() => {
    axios.post('http://localhost:8080/api/something',{credential: sessionStorage.getItem("token")}
    ).then(function (res){
        console.log("setting IsAuth")
        console.log(res.data["UserAuth"])
        // console.log(Boolean(res.data["UserAuth"]));
        setIsAuth(res.data["UserAuth"]);
        return isAuth;
      });
  });

  console.log(isAuth);

  if (isAuth === undefined) return null; // or loading indicator, etc...

  return isAuth==="true" ? <Outlet /> : <Navigate to="/login/Client" />;
}

Attaching the logs here for reference.

enter image description here

Upvotes: 0

Drew Reese
Drew Reese

Reputation: 202696

A couple issues, (1) you are issuing the POST request as an unintentional side-effect, and (2) the code is asynchronous whereas the body of a React component is synchronous.

Use a mounting useEffect hook to issue the POST request and wait for the request to resolve. Use an intermediate isAuth state value to "hold" until the POST request resolves either way if the user is authenticated or not.

function PrivateRouteClient() {
  const [isAuth, setIsAuth] = useState(); // initially undefined

  useEffect(() => {
    axios.post(
      'http://localhost:8080/something/something',
      { credential: sessionStorage.getItem("token") },
    )
      .then(function (res){
        console.log(Boolean(res.data["UserAuth"]));
        setIsAuth(Boolean(res.data["UserAuth"]));
        return isAuth;
      });
  }, []);

  console.log(isAuth);

  if (isAuth === undefined) return null; // or loading indicator, etc...

  return isAuth ? <Outlet /> : <Navigate to="/login/Client" />;
}

Upvotes: 3

Related Questions