0

How I can fix my router? I am using redux to handle logout but when logout, it will direct me to 404 page then to login page. I tried to put exact to the routes and made the 404 route last in the list of the routes. My website has different user roles so I think the bug is related to that.

<Routes>
  <Route path={ROUTES.Error} element={<NotFound />} />

  <Route path={ROUTES.home} element={<Private />}>
    {pages
      .filter((page) =>
        page.hasAccess.some((role) =>
          _.isEqual(role, user?.info?.RoleCode),
        ),
      )
      .map(({ id, path, element: Element }) => (
        <>
          <Route
            key={id}
            path={ROUTES.home}
            element={<Navigate replace to="dashboard" />}
          />,
          <Route key={id} path={path} element={<Element />} />
        </>
      ))}
  </Route>
  <Route
    path=""
    element={<Public />}
    children={<Route path={ROUTES.login} element={<Login />} />}
  />
</Routes>

Under saga Logout

function* logout() {
  yield put(userSlice.actions.logoutFulfilled(null));
  socket.disconnect();
  yield new Promise(() => {
    notification.success({
      message: 'Success',
      description: 'Logout Success',
    });
  });
}
  • You are conditionally rendering some routes it seems, so I'd look at that. Generally you want to ***unconditionally*** render your routes and handle the route protection as a layout route. See if this [answer](/a/66289280/8690857) helps explain route protection. Also, why are you rendering a redirect to `"dashboard"` for each protected route being mapped? – Drew Reese Jan 03 '23 at 04:21
  • Which route is your "404" route? `} />`? Can you [edit] to include the "logging out" code and component as part of a complete [mcve]? – Drew Reese Jan 03 '23 at 07:41
  • @DrewReese I think it is because of user roles , because when I logout , the user.info in redux is null. And I tried to access other page that has user role requirements in the login page, it directed me to the 404 page because I don't have access – user18528865 Jan 03 '23 at 07:58
  • So calling/dispatching `logout` doesn't effect a navigation action. Where are you logging out from? Is *that* code trying to navigate somewhere upon successful logout, or this is really it, you log out and update the Redux store (and user roles), and the UI freaks out for a moment redirecting to a route that can be matched? I still think you should update your post to include a more complete [mcve]. – Drew Reese Jan 03 '23 at 08:01
  • I tried to put setTimeout(() => (window.location = ROUTES.login), 100); on logout function, sometimes it will not direct me to 404 page but still 404 page occurs – user18528865 Jan 03 '23 at 08:04

1 Answers1

1

It seems the issue here is that the code is conditionally rendering routes based on the current user object's roles. The protected routes are unmounted prior to any user check happening, so the UI momentarily renders the "404" route then the auth check occurs and redirects user to log in.

You should generally unconditionally render the routes so that they are always mounted and matchable, and use layout routes to render route protectors.

It's unclear what the Private route is doing specifically, so I'll answer by suggesting you create a RoleWrapper component that inspects a route's access roles against the current user.info.RoleCode property. If the current user has the appropriate roles then the children prop is rendered, otherwise a redirect to a safe, non-protected route is rendered.

const RoleWrapper = ({ children, roles }) => {
  const { user } = /* however the user object is accessed */

  // Handles initial mount if user object is fetched
  if (user === undefined) {
    return null; // or loading indicator/spinner/etc
  }

  const canAccess = roles.some(
    (role) => _.isEqual(role, user?.info?.RoleCode),
  );

  return canAccess
    ? children
    : <Navigate to="/dashboard" replace />; // or any safe route
};
<Routes>
  <Route path={ROUTES.Error} element={<NotFound />} />
  <Route path={ROUTES.home} element={<Private />}>
    {pages.map(({ element: Element, hasAccess, id, path }) => (
      <Route
        key={id}
        path={path}
        element={(
          <RoleWrapper roles={hasAccess}>
            <Element />
          </RoleWrapper>
        )}
      />
    ))}
  </Route>
  <Route element={<Public />}>
    <Route path={ROUTES.login} element={<Login />} />
  </Route>
</Routes>
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • 1
    Thank you sir @Drew Reese, actually I fixed it. I just added a OR condition on filter. I added _.isNil(user.info). But I like to try your implementation. Thank you so much . I learned a lot – user18528865 Jan 03 '23 at 08:35