'How to create HOC component with protected route?

I'm using react-router dom v6 and I have ProtectedRoute like

export const ProtectedRoute = ({
  children,
}: {
  children: JSX.Element;
}) => {
  let location = useLocation();

  const auth = useAuth();


  if (!auth.isAuthenticated) {
    return <Navigate to="/login" state={{ from: location }} />;
  }

  // if (isAuthenticated && !userHasRequiredRole) {
  //   return <AccessDenied />;
  // }

  return children;
};

In my AppRouter

const AppRouter = () => {
  let elements = useRoutes([
    // These are the same as the props you provide to <Route>
    { path: '/login', element: <LoginPage /> },
    {
      path: '/',
      element: (
        // [1] 👈
        <ProtectedRoute>
          <BasicLayout />
        </ProtectedRoute>
      ),
      children: [
        {
          path: 'sale',
          element: (
            // [2] 👈
            <ProtectedRoute>
              <Sale />
            </ProtectedRoute>
          ),
        }
      ]
    }
  ])
  return elements
}
  1. Can I create HOC component so I dont need to write like this over time (.ie WithProtectedRoute) ?
  2. Do I need to put the component inside ProtectedRoute every time like this since I put in on path: '/'?


Solution 1:[1]

While you could create a withProtectedRoute HOC and wrap each component export you want to protect, there's a more "react-router-dommethod. Instead of rendering achildrenprop you could render anOutletcomponent for nestedRoutecomponent and render theProtectedRoute` now as a layout component.

Example:

import { Navigate, Outlet } from 'react-router-dom';

export const ProtectedRoute = () => {
  const location = useLocation();

  const auth = useAuth();

  return auth.isAuthenticated
    ? <Outlet />
    : <Navigate to="/login" state={{ from: location }} replace />;
};

...

const elements = useRoutes([
  // These are the same as the props you provide to <Route>
  { path: '/login', element: <LoginPage /> },
  {
    element: <ProtectedRoute />,
    children: [
      {
        path: '/',
        element: <BasicLayout />,
        children: [
          {
            path: 'sale',
            element: <Sale />,
          }
        ],
      },
    ],
  },
]);

Read more about layout routes here.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drew Reese