I want to check if the user is logged in on page reload (F5). To do this, I call the useLayoutEffect hook in the _app.tsx file:
const { authenticated, setAuthenticated } = useContext(AuthContext)
const fetchRefresh = async () => {
const status = await AuthStore.checkAuth()
if (status == 200) {
setAuthenticated && setAuthenticated(true)
} else {
setAuthenticated && setAuthenticated(false)
}
return status
}
useLayoutEffect(() => {
if (localStorage.getItem("access_token")) {
fetchRefresh()
}
}, [])
My index.tsx is wrapped in a Layout where I call useEffect and check the user state from the context:
export const withLayout = <T extends Record<string, unknown> & IAuthContext>(Component: FunctionComponent<T>) => {
return function withLayoutComponent(props: T): JSX.Element {
const { authenticated } = useContext(AuthContext)
const router = useRouter()
useEffect(() => {
if (!authenticated) router.push("/auth/login")
}, [authenticated])
return (
<Layout>
<Component {...props} />
</Layout>
);
};
};
The order of the logs in the console is as follows:
- useLayoutEffect(_app.tsx)
- use effect (index.tsx)
- complete the fetchRefresh function
The login page also has a useEffect that redirects to the "/" page if the user is logged in. So when I reload the page, I have a flicker and a few redirects that I want to get rid of.
And another question, why?
setAuthenticated && setAuthenticated(true)
console.log(authenticated) // print false
CodePudding user response:
First reason is technical: you don't await for fetchRefresh()
. It just runs async operation and promise returns is ignored, nothing rely/check it.
Second reason, useEffect
/useLayoutEffect
are not blocking rendering, and even does not expect async operations. So (even) if you do it as
useLayoutEffect(() =>
if (localStorage.getItem("access_token")) {
await fetchRefresh()
}
first render would still happen anyway, and with authenticated == true
.
You need to change your logic in some way. Either add a boolean isLoading
so first render would not show anything since data is still being fetched/verified. Or instead of boolean for authenticated
you can use enum yes|true|undefined
and for last value does not do/show anything. Or do something else.