skip to Main Content

In React-Router-Dom 6 I am using useRoutes and so I build a route object. I have a route where I want the top of the route to have a layout, and then different outlets based on the param.

So for example:

/wizard/step1 -> Step1Page
/wizard/step2 -> Step2Page

The way I built this, looks like:

const routes = [
  {
    path: '/wizard/:step',
    element: <WizardLayout />, // this has an <Outlet />
    children: [
      {
        path: '/wizard/step1',
        element: <Step1Page />,
      },
      {
        path: '/wizard/step2',
        element: <Step2Page />,
      },
    ],
  },
];

This throws an error, saying that child paths "must begin with full paths of their parents". This means that the layout should have a path like:

{
  path: '/wizard',
  element: <WizardLayout />,
  children: [ ... ],
}

However, doing it like this makes the children elements not recognize the :step param when calling useParams because it’s not actually defined in the route.

To reiterate, I want the layout to apply to all routes of type /wizard/:step, and to have specific elements in specific :step params. How can I do that?

2

Answers


  1. in react router using :step means that you want the route to include dynamic value but in your case there is nothing dynamic, so change the code to

    const routes = [
      {
        path: '/wizard',
        element: <WizardLayout />, // this has an <Outlet />
        children: [
          {
            path: 'step1',
            element: <Step1Page />,
          },
          {
            path: 'step2',
            element: <Step2Page />,
          },
        ],
      },
    ];
    

    where the layout has the Outlet and it will render the child route accordingly

    A case where if you do want a dynamic route say you want an id to be part of a route which you will get by clicking something then that is when you use the :id to set it as part of the route

    Login or Signup to reply.
  2. As the error indicates, you can’t nest the absolute path "/wizard/step1" under the absolute path "/wizard/:step". To have a dynamic path segment step available to WizardLayout then you have a few options.

    1. Move the children routes into a switch statement in WizardLayout to replace the Outlet.

      const router = createBrowserRouter([
        ...
        {
          path: '/wizard/:step',
          element: <WizardLayout />,
        },
        ...
      ]);
      
      const WizardLayout = () => {
        const { step } = useParams();
      
        const getStep = () => {
          switch(step) {
            case "step1":
              return <Step1Page />;
      
            case "step2":
              return <Step2Page />;
      
            default:
              return null;
          }
        }
      
        return (
          <>
            ... Wizard Layout UI ...
            {getStep()}
            ...
          </>
        )
      };
      

      Edit wizardly-easley-thq4df

    2. Update the route declarations so the nested routes can work and use the useMatch hook in WizardLayout to get a match to a "/wizard/:step" path.

      const router = createBrowserRouter([
        ...
        {
          path: '/wizard',
          element: <WizardLayout />,
          children: [
            {
              path: 'step1',
              element: <Step1Page />,
            },
            {
              path: 'step2',
              element: <Step2Page />,
            },
          ],
        },
        ...
      ]);
      
      import { Outlet, useMatch } from 'react-router-dom';
      
      const WizardLayout = () => {
        const match = useMatch('/wizard/:step');
        const { step } = match?.params;
      
        return (
          <>
            ... Wizard Layout UI ...
            <Outlet />
            ...
          </>
        )
      };
      

      Edit react-router-6-how-to-define-child-routes-for-specific-params (v2)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search