skip to Main Content

This is the private route component, and before users access the page I need to check if they are logged in (if their token is valid)

import { authService } from '../authservice/AuthService';

export default function PrivateRoute({ children }: { children: JSX.Element }) {
  //const isLoggedIn = authService.isLoggedIn();
  let location = useLocation();

  if (!isLoggedIn) {
    return <Navigate to="/login" state={{ from: location }} />;
  }
  return children;
}

This is the function I’m trying to call inside the PrivateRoute component

class AuthService {

    api_domain = "http://localhost:5000"

    async isLoggedIn() {

        if (!this.getToken() || typeof this.getToken() != 'string') {
            return false
        }

        axios.get(this.api_domain + "/", {headers: {Authorization: this.getToken()}})
        .then(res => {
            if (res.data.status === 'ok') {
                return true
            }
            return false
        })

    }
}

2

Answers


  1. The reason the isLoggedIn function needs to be async is because it makes a request to your server, something which actually takes time. Therefore, what you want to be doing is displaying some sort of loading state until the user has been verified by the server.

    You can create a custom hook which returns two states, isLoading and isLoggedIn, initializing isLoading as true:

    export function useIsLoggedIn() {
      const [isLoggedIn, setIsLoggedIn] = useState(false);
      const [isLoading, setIsLoading] = useState(true);
    
      useEffect(() => {
            const token = getToken();
            if (!token || typeof token !== 'string') {
              setIsLoading(false);  
              return;
            }
    
            axios.get(api_domain + "/", {headers: {Authorization: token}})
            .then(res => {
                if (res.data.status === 'ok') {
                    setIsLoggedIn(true);
                }
                setIsLoading(false);
            })
            .catch(() => setIsLoading(false));
      }, []);
    
      return { isLoggedIn, isLoading };
    }
    

    Then, in your PrivateRoute component, you can use this to ensure that the verification has already happened:

    export default function PrivateRoute({ children }: { children: JSX.Element }) {
      const { isLoggedIn, isLoading } = useIsLoggedIn();
      const location = useLocation();
    
      if (isLoading) {
        return <div>Loading...</div>; // or some other loading state
      }
    
      if (!isLoggedIn) {
        return <Navigate to="/login" state={{ from: location }} />;
      }
    
      return children;
    }
    
    Login or Signup to reply.
  2. The useEffect and useState hooks will help you out here.

    import { useEffect, useState } from 'React';
    import { authService } from '../authservice/AuthService';
    
    export default function PrivateRoute({ children }: { children: JSX.Element }) {
      let location = useLocation();
      const [loggedIn, setLoggedIn] = useState(false);
      const [loading, setLoading] = useState(true);
      
      useEffect(() => {
        const isLoggedIn = async () => {
          const value = await authService.isLoggedIn();
          setLoggedIn(value);
        }
    
        
        // Invoke the async function
        isLoggedIn();
    
      }, [])
      
    
      if (loading){ 
        return <div>Loading...</div>
      } 
    
      if (!loggedIn) {
        return <Navigate to="/login" state={{ from: location }} />;
      }
      return children;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search