0

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?

Alexander
  • 24
  • 4

1 Answers1

1

Like you said, the checkAuth function is asynchronous, therefore you would need to await the result of the checkAuth funtion inside your useEffect hook:

useEffect(() => {
    async function auth() {
      if (localStorage.getItem('token')) {
         await checkAuth();
      }
    }
    auth()
  }, []);
  • thank you, but it wasn't the main problem. I noticed It's actually working when navigating to the /dashboard route using Link component from react-router-dom. However, if I manually change the path in the address bar, it refreshes the page and it causes this problem – Alexander Jul 29 '23 at 19:53