Convert from react router dom v5 to react router dom v6 when using useRouteMatch

Viewed 385

I am having issues with what the new syntax should be when it comes to migrating from React Router V5 to React Router V6.

I am new to V6 but in V5 I was using the following code within the component name: MyComponent.js

RR V5

 const theRoute = useRouteMatch();
  const myRoutes = [
    ['Tab One', theRoute.url],
    ['Tab Two', `${theRoute.url}/details`]
 ];

Use Case currently for V5:

  <AppBar
      position="static"
      color="primary"
    >
      <Tabs
        value={location.pathname}
        textColor="inherit"
      >
        <Tab
          label={myRoutes[0][0]}
          value={myRoutes[0][1]}
          component={Link}
          to={myRoutes[0][1]}
        />
        <Tab
          label={myRoutes[1][0]}
          value={myRoutes[1][1]}
          component={Link}
          to={myRoutes[1][1]}
        />
      </Tabs>
    </AppBar>

    <div>
      <Switch>
        <Route path={routes[0][1]}>
          <Main />
        </Route>
        <Route path={routes[1][1]}>
          <ShowDetails />
        </Route>
      </Switch>
    </div>

Within App.js (parent level), I have a route that calls the above MyComponent.js component, which has nested routes.

<div>
  <Switch>
    <Route path="/info/:id">
      <MyComponent />
    </Route>
  </Switch>
</div>

I realise that useRouteMatch() is no longer available in RR V6 but unsure how to achieve the same result I used in V5 above, now in V6?

I looked at useLocation() but it didn't seem to work.

1 Answers

App

  • Switch the Switch component for the Routes component that replaced it in v6
  • Move MyComponent into the Route component's element prop, passed as a ReactNode, a.k.a. JSX.
  • Include a trailing route path wildcard character "*" at the end of the path so nested routes can also be matched by this route.

Example:

<div>
  <Routes>
    <Route path="/info/:id/*" element={<MyComponent />} />
  </Routes>
</div>

MyComponent

  • Wrap the nested routes in a Routes component so route matching works. Nested Routes components will build paths relative from the parent route rendering them.
  • Move the routed children components into the Route component's element prop.
  • I suggest making the code more DRY by moving the component you want to render for each route into the myRoutes config and convert to objects from arrays, and map the myRoutes config to the JSX.

Example:

const myRoutes = [
  {
    name: 'Tab One',
    path: "main",
    element: <Main />,
  },
  {
    name: 'Tab Two',
    path: "details",
    element: <ShowDetails />,
  },
];

...

const { pathname } = useLocation();

// Compute the "last path segment" to use for the `Tabs` component
// `value` prop. The last path segment will match against the paths
// that are used for the `Tab` component's `value` prop.

const lastSegment = pathname.split("/").slice(-1).join();

...

<AppBar position="static" color="primary" >
  <Tabs
    value={lastSegment}
    textColor="inherit"
  >
    {myRoutes.map(({ name, path }) => (
      <Tab
        key={path}
        label={name}
        value={path}
        component={Link}
        to={path}
      />
    ))}
  </Tabs>
</AppBar>

<div>
  <Routes>
    {myRoutes.map(({ element, path }) => (
      <Route key={path} path={path} element={element} />
    ))}
  </Routes>
</div>
Related