I have a React project using react-router-dom and Zustand libraries. I want to protect the DashLayout route and its children. Here's my App component:
const App = () => {
const checkAuth = useAuthStore((state) => state.checkAuth);
{
/* checkAuth() function below checks if the user is authenticated (runs on initial
render) */
}
useEffect(() => {
if (localStorage.getItem('token')) {
checkAuth();
}
}, []);
return (
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Public />} />
<Route path="login" element={<Login />} />
<Route path="register" element={<SignUp />} />
{/* Protect this route and its children */}
<Route path="dashboard" element={<DashLayout />}>
<Route index element={<Profile />} />
</Route>
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
);
};
And this is Zustand store and the checkAuth function in particular:
export const useAuthStore = create()(
devtools((set) => ({
user: {},
isAuth: false,
isLoading: false,
// ======= This function checks if the user is authenticated ===
checkAuth: async () => {
set({ isLoading: true });
try {
const response = await axios.get(`${API_URL}/auth/refresh`, {
withCredentials: true
});
console.log(response);
localStorage.setItem('token', response.data.accessToken);
set({ user: response.data.user, isAuth: true });
} catch (error) {
console.error(error.response.data);
} finally {
set({ isLoading: false });
}
}
}))
);
The problem is in the DashLayout component. The isAuth variable is false when it renders, because the checkAuth function is asynchronous:
const DashLayout = () => {
const isAuth = useAuthStore((state) => state.isAuth);
return isAuth ? <Outlet /> : <Navigate to="/login" />;
};
So how to "make it wait" for the correct value of isAuth?