I created simple user context in react:
UserProvider
export const AuthContext = createContext();
export const AuthProvider = ({children}) => {
const [user, setUser] = useState(null);
useEffect(() => {
//Call server
const loginUser = {
userId: 1,
role: "Admin"
}
setUser(loginUser)
}, []);
return (
<AuthContext.Provider value={{user}} >{children}</AuthContext.Provider>
);
};
useAuth
const useAuth = () => {
const user = useContext(AuthContext);
if (user === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return user;
};
export default useAuth;
App
return (
<AuthProvider>
<BrowserRouter>
<Routes>
<Route path="/Login" element={<Login/>}/>
<Route element={<ProtectedRoutes />}>
<Route path="/User/Profile" element={<Profile/>}/>
</Route>
</Routes>
</BrowserRouter>
</AuthProvider>
);
Protected Routes
const ProtectedRoutes = () => {
const {user} = useAuth();
return(
user ? <Outlet/> : <Navigate to="/login"/>
)
}
export default ProtectedRoutes
Everything works fine, but when I refresh the page in User/Profile when user is logged,it anyway redirects me to login. Console log in Protected routes when i refresh the page looks like this:
null
{userId: 1, role: 'Admin'}
I know that this problem probably occurs because "user" is null when first rendered, but I have no idea how to fix it.Could anyone tell me how i can improve it?
CodePudding user response:
You can keep a app state and redirect only when app authenticated
Here is a good article by Kent C. Dodds on how to handle authentication
export const AuthContext = createContext();
export const AuthProvider = ({children}) => {
const [appState, setAppState] = useState({ user: null, state: 'loading' });
useEffect(() => {
//Call server
const loginUser = {
userId: 1,
role: "Admin"
}
setUser({
user: loginUser,
state: 'loaded'
})
}, []);
return (
<AuthContext.Provider value={appState} >{children}</AuthContext.Provider>
);
};
const useAuth = () => {
const state = useContext(AuthContext);
if (state === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return { ...state };
};
export default useAuth;
handling app state in ProtectedRoutes
const ProtectedRoutes = () => {
const { user, state } = useAuth();
if (state === 'loading') {
return <div>Loading...</div>
}
return(
user ? <Outlet/> : <Navigate to="/login"/>
)
}
export default ProtectedRoutes
Or rendering the protected routes only after app is loaded
const AppRoutes = () => {
const { user, state } = useAuth();
if (state === 'loading') {
return <div>Loading...</div>
}
return user ?
<AuthenticatedRoutes>
: UnAuthenticatedRoutes />
}
return (
<AuthProvider>
<BrowserRouter>
<AppRoutes />
</Routes>
</BrowserRouter>
</AuthProvider>
);
Hope this helps in some way