So I have this kind of issue, having a React Context where I manage authentication I use a protected routes component to disable accessing pages when the user is not authenticated (no localstorage user data available).
But there is a problem with this approach, because at the first pre-render the user is undefined (useState()
) and only after useEffect runs the user data is fetched.
Snippet code:
AuthContextProvider
const [user, setUser] = useState();
const [hydrated, setHydrated] = useState(false); // added to fix the problem
useEffect(() => {
const userLocal = localStorage.getItem('user');
setUser(JSON.parse(userLocal));
setHydrated(true); // added to fix the problem
}, []);
Protected routes:
if (isBrowser() && !authCtx.user && pathIsProtected) {
router.push('/signin');
}
So I end up having user = undefined for a fraction of second that is enough to catch the condition !authCtx.user
, instead the user is authenticated.
As you can see in the code my workaround that works is to use a hydrated
variable which I set together with the user data from localstorage and in the provider I wait the hydrated variable to be true before rendering the children components (where the protected route is)
return (
<AuthContext.Provider
value={{
error: error,
loading: loading,
user: user
}}
>
{hydrated && children} {/* added to fix the problem */}
</AuthContext.Provider>
);
This way everything works fine but is this the right pattern for this kind of problem?
CodePudding user response:
You can do this, which is almost the same but uses user
variable instead of hydrated
:
const [user, setUser] = useState(false);
And in the component:
...
>
{user && children} {/* added to fix the problem */}
</AuthContext.Provider>
...
This way you can drop const [hydrated, setHydrated] = useState(false);
altogether.