Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I always get redirected to home page when refresh any page

I traveled through topics similar situation to mine, but I still not found the solution to my case.

When I implemented checking token function on app.js to generate code for Unauthenticated User redirect to Signin page and Authenticated User jump to Hompage.

However, after this part my SPA started getting redirect to home page from any page when refreshing/F5.

Below is my authContext.js:

export const AuthContext = createContext({
  token: null,
  userId: null,
  isLoggedIn: false,
  login: (userId, token) => {},
  logout: () => {},
});

const AuthContextProvider = (props) => {
  const [userId, setUserId] = useState();
  const [token, setToken] = useState();

  const loginUserHandler = useCallback((userId, token) => {
    setUserId(userId);
    setToken(token);
    localStorage.setItem("userData", JSON.stringify({ userId, token }));
  }, []);

  const logoutUserHandler = useCallback(() => {
    setUserId(null);
    setToken(null);
    localStorage.removeItem("userData");
  }, []);

  const initialValues = {
    userId: userId,
    token: token,
    isLoggedIn: !!token,
    login: loginUserHandler,
    logout: logoutUserHandler,
  };

  return <AuthContext.Provider value={initialValues}>{props.children}</AuthContext.Provider>;
};

export default AuthContextProvider;

And app.js code

function App() {
  const { token, login } = useContext(AuthContext);
  let routes;

  useEffect(() => {
    const storedData = JSON.parse(localStorage.getItem("userData"));
    if (storedData && storedData.token) {
      login(storedData.userId, storedData.token);
    }
  }, [login]);

  if (token) {
    routes = (
      <Layout>
        <Switch>
          <Route path="/home" exact>
            <Home />
          </Route>
          <Route path="/leads-manager" exact>
              <Leads />
          </Route>
          <Route path="/phone-manager" exact>
              <Phone />
          </Route>
          <Route path="/new-notifications" exact>
            <Notification />
          </Route>
          <Redirect to="/home" exact />
        </Switch>
      </Layout>
    );
  } else {
    routes = (
      <Switch>
        <Route path="/sign-in" exact>
          <Login />
        </Route>
        <Redirect to="/sign-in" />
      </Switch>
    );
  }

  return <BrowserRouter>{routes}</BrowserRouter>;
}

export default App;
like image 692
J.Tran Avatar asked Oct 16 '25 01:10

J.Tran


1 Answers

The issue is that you don't initialize the token state from localStorage in the AuthContextProvider component when the component mounts. When you reload the page all React state will be lost since it exists only in memory. token is falsey and the App component renders the "unauthenticated" route/redirect. I believe what is happening is the token is falsey and the user is bounced to "/sign-in" and at the same time the useEffect hook in App pulls from local storage and authenticates the user, which updates the userId and token states. token is defined now and the "authenticated" routes render, and because the URL path is still "/sign-in" the Redirect to "/home" is rendered.

Use useEffect hooks to (A) persist state changes to localStorage and (B) initialize the userId and token states.

const AuthContextProvider = ({ children }) => {
  const [userId, setUserId] = useState();
  const [token, setToken] = useState();

  // Effect to initialize local state and reauthenticate
  useEffect(() => {
    const { userId, token } = JSON.parse(localStorage.getItem("userData")) || {};
    if (userId) setUserId(userId);
    if (token) setToken(token);

    if (userId && token) {
      login(userId, token);
    }
  }, []);

  useEffect(() => {
    if (token || userId) {
      localStorage.setItem("userData", JSON.stringify({ userId, token }));
    } else {
      localStorage.removeItem("userData");
    }
  }, [token, userId]);

  const loginUserHandler = useCallback((userId, token) => {
    setUserId(userId);
    setToken(token);
  }, []);

  const logoutUserHandler = useCallback(() => {
    setUserId(null);
    setToken(null);
  }, []);

  const initialValues = {
    userId: userId,
    token: token,
    isLoggedIn: !!token,
    login: loginUserHandler,
    logout: logoutUserHandler,
  };

  return (
    <AuthContext.Provider value={initialValues}>
      {children}
    </AuthContext.Provider>
  );
};

Update the App component to explicitly check if the token is undefined when the component mounts to conditionally return early so neither the "authenticated" or "unauthenticated" routes/redirect logic are applied.

function App() {
  const { token } = useContext(AuthContext);

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

  return (
    <BrowserRouter>
      {token
        ? (
          <Layout>
            <Switch>
              <Route path="/home" component={Home} />
              <Route path="/leads-manager" component={Leads} />
              <Route path="/phone-manager" component={Phone} />
              <Route path="/new-notifications" component={Notification} />
              <Redirect to="/home" />
            </Switch>
          </Layout>
        )
        : (
          <Switch>
            <Route path="/sign-in" component={Login} />
            <Redirect to="/sign-in" />
          </Switch>
        )
      }
    </BrowserRouter>
  );
}

export default App;
like image 89
Drew Reese Avatar answered Oct 18 '25 19:10

Drew Reese