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;
2
Answers
I have changed code a little bit I added one more state to check display the
Loader.js
(mainly for preventing route redirection to hit unwanted routes)First time runs project
hasInitVal = false
will show theLoader.js
. Afterapp.js
component mount and useEffect function get executed, value ofhasInitVal
changed andapp.js
reload again to display corresponding routes base on the token values.autContext.js
fileapp.js
fileThe issue is that you don’t initialize the
token
state from localStorage in theAuthContextProvider
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 theApp
component renders the "unauthenticated" route/redirect. I believe what is happening is thetoken
is falsey and the user is bounced to"/sign-in"
and at the same time theuseEffect
hook inApp
pulls from local storage and authenticates the user, which updates theuserId
andtoken
states.token
is defined now and the "authenticated" routes render, and because the URL path is still"/sign-in"
theRedirect
to"/home"
is rendered.Use
useEffect
hooks to (A) persist state changes to localStorage and (B) initialize theuserId
andtoken
states.Update the
App
component to explicitly check if thetoken
is undefined when the component mounts to conditionally return early so neither the "authenticated" or "unauthenticated" routes/redirect logic are applied.