skip to Main Content

Here I’m trying to navigate to "/home" route using useNavigate() hook right after the login request is successful. Instead of routing to ‘/home’, its reloading the "/login".
Here I’m attaching code

App.js

export default function App() {
  const router = createBrowserRouter([{
    path: '/',
    element: isUserValid() ? <Navigate to="/home" replace /> : <Navigate to="/login" replace />,
    errorElement: <Error />
  },
  {
    path: '/login',
    element: !isUserValid() ? <Login /> : <Navigate to="/home" replace />
  }, {
    path: '/register',
    element: !isUserValid() ? <Register /> : <Navigate to="/home" replace />
  },
  {
    path: '/home',
    element: isUserValid() ? <Form /> : <Navigate to="/login" replace />
  }])
  return (
    <RouterProvider router={router} />
  )
}

In the above isUserValid() returns true or false based on the session maintained in localStorage.

Login.js

const handleSubmit = async (e) => {
        const isValid = onSubmit(e);
        if (isValid) {
            const payLoad = {};
            for (let key in formData) {
                payLoad[key] = formData[key]['value'];
            }
            try {
                const response = await login(payLoad);
                localStorage.setItem('user', JSON.stringify(response.data));
                debugger;
                console.log("//== before navigation")
                navigate('/home', { replace: true });
            } catch (err) {
                console.log("inside login error");
                setApiErrorMessage(err.response.data.error);
            }
        }
    }

The above code is for form submission, I’m able to get the token from the backend and able to store it in localStorage.

Here is the problem occures, I’m unable to re route to ‘/home’. Please provide me a solution.

2

Answers


  1. Since setting to local storage is an asynchronous operation, navigation might be taking place before value is set to local storage and the isUserValid function might be returning false, hence redirecting to login.

    Login or Signup to reply.
  2. It looks like you might be running into a race condition where the route is being updated before the isUserValid() function can read the updated local storage value. To resolve this issue, you can use a state management solution like React context or Redux to manage the user’s authentication status. For simplicity, I’ll show you an example using React context.

    First, create a new file named AuthContext.js:

    import { createContext, useState, useContext, useEffect } from 'react';
    
    const AuthContext = createContext();
    
    export const useAuth = () => {
      return useContext(AuthContext);
    };
    
    export const AuthProvider = ({ children }) => {
      const [isAuthenticated, setIsAuthenticated] = useState(false);
    
      useEffect(() => {
        const user = localStorage.getItem('user');
        if (user) {
          setIsAuthenticated(true);
        }
      }, []);
    
      const login = (user) => {
        localStorage.setItem('user', JSON.stringify(user));
        setIsAuthenticated(true);
      };
    
      const logout = () => {
        localStorage.removeItem('user');
        setIsAuthenticated(false);
      };
    
      const value = {
        isAuthenticated,
        login,
        logout,
      };
    
      return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
    };
    

    Now, update your App.js to use the AuthProvider:

    import { AuthProvider } from './AuthContext';
    
    export default function App() {
      // ... router setup ...
    
      return (
        <AuthProvider>
          <RouterProvider router={router} />
        </AuthProvider>
      );
    }
    

    Update the routes in App.js to use the useAuth() hook:

    import { useAuth } from './AuthContext';
    
    export default function App() {
      const { isAuthenticated } = useAuth();
    
      const router = createBrowserRouter([
        // ...
        {
          path: '/login',
          element: !isAuthenticated ? <Login /> : <Navigate to="/home" replace />,
        },
        {
          path: '/register',
          element: !isAuthenticated ? <Register /> : <Navigate to="/home" replace />,
        },
        {
          path: '/home',
          element: isAuthenticated ? <Form /> : <Navigate to="/login" replace />,
        },
      ]);
    
      return (
        <AuthProvider>
          <RouterProvider router={router} />
        </AuthProvider>
      );
    }
    

    Finally, update your Login.js to use the login function from the AuthContext:

    import { useAuth } from './AuthContext';
    
    // ...
    
    const Login = () => {
      // ...
      const { login } = useAuth();
      const navigate = useNavigate();
    
      const handleSubmit = async (e) => {
        // ...
    
        try {
          const response = await someApi.login(payLoad);
          login(response.data); // Update this line to use the login function from the AuthContext
          navigate('/home', { replace: true });
        } catch (err) {
          // ...
        }
      };
    
      // ...
    };
    

    By using a context, you can manage the authentication status more effectively and avoid race conditions caused by reading from local storage. This should resolve the issue you’re experiencing.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search