Home > Enterprise >  How to handle 404 on react-router-dom v6?
How to handle 404 on react-router-dom v6?

Time:01-03

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',
    });
  });
}

CodePudding user response:

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>

CodePudding user response:

It is very simple, you just have to use.

<Routes>
   <Route path="*" element={<NotFound />} />
</Routes>
  • Related