protected routes in react js app always returns undefined

Viewed 19

here is my protectedroute component am using react-router-dom v6 and accessing the token from localStorage and either ways user is always returning undefined

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

const ProtectedRoute = () => {
  const userAuth = () => {
    axios.get("http://localhost:5000/isUserAuth", {
      headers: {
      "x-access-token": localStorage.getItem("token")
    }}).then((response) => {
      console.log(response.data)
      if(response.data.auth) {
        console.log(true)
        return true;
        
      } else {
        console.log(false)
        return false;
      }
    })
  }

  let auth = userAuth()
  console.log("auth",auth)

  return (
    auth? <Outlet/> : <Navigate to="/"/>
  )
}

export default ProtectedRoute

my app.js

function App() {
  return (
    <BrowserRouter>
        <ToastContainer position='top-center'/>
        <Routes>
            <Route element={<ProtectedRoutes/>}>
              <Route exact path='/home' 
                element={< Home />}/> 
              <Route exact path='/add' 
                element={< AddCust />} /> 
              <Route exact path='/update/:id' 
                element={< AddCust />} /> 
              <Route exact path='/view/:id' 
                element={< View />} /> 
              <Route exact path='/table' 
                element={< Table />} /> 
              <Route exact path='/edit-order/:id' 
                element={< Table />} /> 
                <Route exact path='/orders' 
                element={< Orders />} /> 
            </Route>
            <Route exact path='/' element={< Login />} /> 
              
        </Routes>
    </BrowserRouter>
    
  );
}

export default App;

this is what is consoled logged enter image description here

which is weired whether a token exists or not auth is always undefined

1 Answers

Nothing is actually returned from the userAuth function, so auth is undefined. While you could return the axios Promise object, this will make userAuth an asynchronous function and not usable as a ternary condition to conditionally render the Outlet component or redirect.

A solution then is to convert auth to a React state, updated in the GET request flow, and conditionally render null or a loading indicator until the auth status resolves.

Example:

const ProtectedRoute = () => {
  const { pathname } = useLocation();

  const [auth, setAuth] = React.useState(); // initially undefined

  React.useEffect(() => {
    const checkAuth = async () => {
      try {
        const response = await axios.get(
          "http://localhost:5000/isUserAuth",
          {
            headers: {
              "x-access-token": localStorage.getItem("token")
            },
          }
        );

        setAuth(!!response.data.auth);
      } catch(error) {
        // handle error, log, etc...
        setAuth(false);
      }
    };

     checkAuth();
  }, [pathname]); // trigger auth check on route change

  if (auth === undefined) {
    return null; // loading indicator/spinner/etc
  }

  return auth
    ? <Outlet/>
    : <Navigate to="/" replace state={{ from: pathname }} />;
};
Related