Home > Mobile >  Condition based routing in react
Condition based routing in react

Time:03-02

I want to render routes based on the user login status.So, I made a function to check if the user is authenticated on the backend using axios and call that function in useEffect in App component and store the respone in the useState. And then I use condition in the Route component's element. If the user is authenticated, redirect the user to home page. If not, redirect to login page. But the problem is when I try to enter the route from url bar, I always get redirected to login page even I'm authenticated.

these are my codes(I removed some unrelated codes to look cleaner)

function App() {

  const navigate = useNavigate();

  const [isLoggedIn, setIsLoggedIn] = useState("NOT_LOGGED_IN");
  const [user, setUser] = useState({});

  const verifyLogin = async () => {
    const res = await axios({
      url: "http://localhost:5000/isloggedin",
      method: "get",
      withCredentials: true
    })
    if (res.data.isLoggedIn && isLoggedIn === "NOT_LOGGED_IN") {
      setIsLoggedIn("LOGGED_IN");
      setUser(res.data.user)
    } else if (!res.data.isLoggedIn && isLoggedIn === "LOGGED_IN") {
      setIsLoggedIn("NOT_LOGGED_IN");
      setUser({})
    }
  }

  useEffect(() => {
    verifyLogin()
  }, [])

  return (
    <div className="App">
      <Routes>
        <Route path='/' element={isLoggedIn === "LOGGED_IN" ? <Home isLoggedIn={isLoggedIn} user={user} /> : <Navigate to="/login" />} exact />
        <Route path='/register' element={<Register handleRegister={handleRegister} registerError={registerError} />} />
        <Route path='/register/:userId/info' element={isLoggedIn === "LOGGED_IN" ? <RegisterInfo handleRegister={handleRegister} registerError={registerError} /> : <Navigate to={"/register"} />} />
        <Route path='/login' element={<Login isLoggedIn={isLoggedIn} handleLogin={handleLogin} logout={logout} />} />
      </Routes>
    </div >
  );

  }

I'm sorry if my writing made you confused. I'm not so good at English.

CodePudding user response:

Issue

The issue is that your initial isLoggedIn state matches your unauthenticated state. When the app initially loads and you are trying to access any route the app uses this "NOT_LOGGED_IN" initial isLoggedIn state value and determines the user is not logged in and redirects accordingly.

Solution

The common solution is to start from an "indeterminant" state that is neither authenticated nor unauthenticated and conditionally render nothing, or a loading indicator, etc... anything but the routed component or the redirect.

Example:

function App() {
  const navigate = useNavigate();

  const [isLoggedIn, setIsLoggedIn] = useState(); // <-- initially undefined
  const [user, setUser] = useState({});

  useEffect(() => {
    const verifyLogin = async () => {
      const res = await axios({
        url: "http://localhost:5000/isloggedin",
        method: "get",
        withCredentials: true
      });

      if (res.data.isLoggedIn && isLoggedIn === "NOT_LOGGED_IN") {
        setIsLoggedIn("LOGGED_IN");
        setUser(res.data.user);
      } else if (!res.data.isLoggedIn && isLoggedIn === "LOGGED_IN") {
        setIsLoggedIn("NOT_LOGGED_IN");
        setUser({});
      }
    };

    verifyLogin();
  }, []);

  if (isLoggedIn === undefined) { // <-- check if undefined
    return null; // or loading indicator, etc...
  }

  return (
    <div className="App">
      <Routes>
        <Route
          path='/'
          element={isLoggedIn === "LOGGED_IN"
            ? <Home isLoggedIn={isLoggedIn} user={user} />
            : <Navigate to="/login" />
          }
        />
        <Route
          path='/register'
          element={(
            <Register
              handleRegister={handleRegister}
              registerError={registerError}
            />
          )}
        />
        <Route
          path='/register/:userId/info'
          element={isLoggedIn === "LOGGED_IN"
            ? (
              <RegisterInfo
                handleRegister={handleRegister}
                registerError={registerError}
              />
            )
            : <Navigate to={"/register"} />
          }
        />
        <Route
          path='/login'
          element={(
            <Login
              isLoggedIn={isLoggedIn}
              handleLogin={handleLogin}
              logout={logout}
            />
          )}
        />
      </Routes>
    </div >
  );
}

Further Suggestions

This makes your code quite a bit more DRY.

  • Related