admin管理员组

文章数量:1125964

I have a router like this

import { createRoot } from 'react-dom/client';
// react-router v7
import { createHashRouter, Link, Outlet, RouterProvider } from 'react-router';

const root = document.createElement('div');
root.setAttribute('id', 'app');
document.body.appendChild(root);

const router = createHashRouter([
  {
    path: 'homepage',
    element: (
      <div>
        <Link to="workspace/1">To workspace 1</Link>
        <br />
        <Link to="foo">To foo</Link>
        <main>
          <Outlet />
        </main>
      </div>
    ),
    children: [
      {
        path: 'workspace/:spaceId/*',
        // I want to lazy load this route, so I use <Routes> to define its sub routes
        element: (
          <div>
            <Link to="setting">To space setting</Link>
            <Routes>
              <Route path="setting" />
            </Routes>
          </div>
        ),
      },
      {
        path: 'foo',
        element: <div>foo</div>,
      },
    ],
  },
]);
createRoot(root).render(
  <RouterProvider router={router} />,
);

The <Link> in homepage work fine. But when I click the 'To space setting' link multiple times, the path become to /homepage/workspace/1/setting/setting/setting....

I don't want to write absolute path in link eg. <Link to="/homepage/workspace/${spaceId}/setting" />. Is there a better way to resolve this issue?

I have tried:

  • Define sub routes in createHashRouter to remove splat, the <Link> works fine. But this is not what I want.
  • Get the current path of the route so I can use <Link to={`${currentPath}/setting`} />, but I didn't find an api for doing so in react-router.

I have a router like this

import { createRoot } from 'react-dom/client';
// react-router v7
import { createHashRouter, Link, Outlet, RouterProvider } from 'react-router';

const root = document.createElement('div');
root.setAttribute('id', 'app');
document.body.appendChild(root);

const router = createHashRouter([
  {
    path: 'homepage',
    element: (
      <div>
        <Link to="workspace/1">To workspace 1</Link>
        <br />
        <Link to="foo">To foo</Link>
        <main>
          <Outlet />
        </main>
      </div>
    ),
    children: [
      {
        path: 'workspace/:spaceId/*',
        // I want to lazy load this route, so I use <Routes> to define its sub routes
        element: (
          <div>
            <Link to="setting">To space setting</Link>
            <Routes>
              <Route path="setting" />
            </Routes>
          </div>
        ),
      },
      {
        path: 'foo',
        element: <div>foo</div>,
      },
    ],
  },
]);
createRoot(root).render(
  <RouterProvider router={router} />,
);

The <Link> in homepage work fine. But when I click the 'To space setting' link multiple times, the path become to /homepage/workspace/1/setting/setting/setting....

I don't want to write absolute path in link eg. <Link to="/homepage/workspace/${spaceId}/setting" />. Is there a better way to resolve this issue?

I have tried:

  • Define sub routes in createHashRouter to remove splat, the <Link> works fine. But this is not what I want.
  • Get the current path of the route so I can use <Link to={`${currentPath}/setting`} />, but I didn't find an api for doing so in react-router.
Share Improve this question edited 2 days ago DisLido asked 2 days ago DisLidoDisLido 274 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

It took a bit of digging through the React-Router v7 CHANGELOG and documentation, but the migration path from RR6 to RR7 relative paths (v7_relativeSplatPath feature flag) is relatively straightforward.

https://reactrouter.com/upgrading/v6#v7_relativesplatpath

  • Split the <Route> into two

    Split any multi-segment splat <Route> into a parent route with the path and a child route with the splat

    Old:

    {
      path: 'workspace/:spaceId/*',
      element: (
        <div>
          <Link to="setting">To space setting</Link>
          <Routes>
            <Route path="setting" />
          </Routes>
        </div>
      ),
    },
    

    Current:

    {
      path: "workspace/:spaceId",
      children: [
        {
          path: "*",
          element: (
            <div>
              <Link to="setting">To space setting</Link>
              <Routes>
                <Route path="setting" element={<h1>Setting</h1>} />
              </Routes>
            </div>
          ),
        },
      ],
    },
    
  • Update relative links

    Update any <Link> elements within that route tree to include the extra .. relative segment to continue linking to the same place

    Old:

    <Link to="setting">To space setting</Link>
    

    Current:

    <Link to="../setting">To space setting</Link>
    

The final key was getting the descendent route element to also render on exactly "/homepage/workspace/:spaceId". For this, make the "workspace/:spaceId" route also an index route.

Final code:

const router = createHashRouter([
  {
    path: "homepage",
    element: (
      <div>
        <Link to="workspace/1">To workspace 1</Link>
        <br />
        <Link to="foo">To foo</Link>
        <main>
          <Outlet />
        </main>
      </div>
    ),
    children: [
      {
        path: "workspace/:spaceId",
        children: [
          {
            index: true,
            path: "*",
            element: (
              <div>
                <Link to="../setting">To space setting</Link>
                <Routes>
                  <Route path="setting" element={<h1>Setting</h1>} />
                </Routes>
              </div>
            ),
          },
        ],
      },
      {
        path: "foo",
        element: <div>foo</div>,
      },
    ],
  },
]);

本文标签: