从 v6 升级
在此页面上

从 v6 升级

React Router v7 需要满足以下最低版本:

  • node@20
  • react@18
  • react-dom@18

如果您已启用所有未来标志,则 v7 升级没有重大变更。这些标志允许您一次进行一项更改来更新您的应用。我们强烈建议您在每个步骤后提交一次更改并发布它,而不是一次性完成所有操作。

更新到最新的 v6.x 版本

首先更新到 v6.x 的最新小版本,以获得最新的未来标志和控制台警告。

👉 更新到最新的 v6 版本

npm install react-router-dom@6

v7_relativeSplatPath

背景信息

此标志更改了多段式通配符路径(如 dashboard/*,而非仅 *)的相对路径匹配和链接行为。查看更新日志了解更多信息。

👉 启用该标志

启用该标志取决于路由器类型

<BrowserRouter
  future={{
    v7_relativeSplatPath: true,
  }}
/>
createBrowserRouter(routes, {
  future: {
    v7_relativeSplatPath: true,
  },
});

更新您的代码

如果您有任何带有路径 + 通配符(例如 <Route path="dashboard/*">)且在其下方带有相对链接(例如 <Link to="relative"><Link to="../relative">)的路由,则需要更新您的代码。

👉 <Route> 拆分为两个

将任何多段式通配符 <Route> 拆分为一个带有路径的父路由以及一个带有通配符的子路由。

<Routes>
  <Route path="/" element={<Home />} />
-  <Route path="dashboard/*" element={<Dashboard />} />
+  <Route path="dashboard">
+    <Route path="*" element={<Dashboard />} />
+  </Route>
</Routes>

// or
createBrowserRouter([
  { path: "/", element: <Home /> },
  {
-    path: "dashboard/*",
-    element: <Dashboard />,
+    path: "dashboard",
+    children: [{ path: "*", element: <Dashboard /> }],
  },
]);

👉 更新相对链接

更新该路由树中的所有 <Link> 元素,使其包含额外的 .. 相对段,以继续链接到相同的位置。

function Dashboard() {
  return (
    <div>
      <h2>Dashboard</h2>
      <nav>
-        <Link to="/">Dashboard Home</Link>
-        <Link to="team">Team</Link>
-        <Link to="projects">Projects</Link>
+        <Link to="../">Dashboard Home</Link>
+        <Link to="../team">Team</Link>
+        <Link to="../projects">Projects</Link>
      </nav>

      <Routes>
        <Route path="/" element={<DashboardHome />} />
        <Route path="team" element={<DashboardTeam />} />
        <Route
          path="projects"
          element={<DashboardProjects />}
        />
      </Routes>
    </div>
  );
}

v7_startTransition

背景信息

这使用 React.useTransition 而不是 React.useState 来更新路由器状态。查看 更新日志 (CHANGELOG) 获取更多信息。

👉 启用该标志

<BrowserRouter
  future={{
    v7_startTransition: true,
  }}
/>

// or
<RouterProvider
  future={{
    v7_startTransition: true,
  }}
/>

👉 更新你的代码

你无需更新任何内容,除非你在组件*内部*使用了 React.lazy

在组件内部使用 React.lazyReact.useTransition(或在组件内部创建 Promise 的其他代码)不兼容。将 React.lazy 移至模块范围,并停止在组件内部创建 Promise。这不是 React Router 的限制,而是 React 的不正确用法。

v7_fetcherPersist

如果你没有使用 <RouterProvider>,可以跳过此项。

背景信息

Fetcher 的生命周期现在基于它何时返回空闲状态,而不是基于其所属组件何时卸载:查看更新日志 (CHANGELOG) 获取更多信息。

启用该 Flag

createBrowserRouter(routes, {
  future: {
    v7_fetcherPersist: true,
  },
});

更新您的代码

这不太可能影响你的应用程序。你可能需要检查 useFetchers 的任何用法,因为它们可能会比以前存在更长时间。根据你的具体操作,你渲染的内容可能会比以前显示更长时间。

v7_normalizeFormMethod

如果你没有使用 <RouterProvider>,可以跳过此项。

这会将 formMethod 字段规范化为大写 HTTP 方法,以与 fetch() 的行为保持一致。查看更新日志 (CHANGELOG) 获取更多信息。

👉 启用该 Flag

createBrowserRouter(routes, {
  future: {
    v7_normalizeFormMethod: true,
  },
});

更新您的代码

如果你的任何代码正在检查小写 HTTP 方法,你需要更新它以检查大写 HTTP 方法(或对其调用 toLowerCase())。

👉 formMethod 与大写进行比较

-useNavigation().formMethod === "post"
-useFetcher().formMethod === "get";
+useNavigation().formMethod === "POST"
+useFetcher().formMethod === "GET";

v7_partialHydration

如果你没有使用 <RouterProvider>,可以跳过此项。

这启用了数据路由器的部分水合(partial hydration),主要用于 SSR 框架,但如果你使用 lazy 来加载路由模块,它也很有用。你不太可能需要为此担心,只需开启该 Flag。查看更新日志 (CHANGELOG) 获取更多信息。

👉 启用该 Flag

createBrowserRouter(routes, {
  future: {
    v7_partialHydration: true,
  },
});

更新您的代码

使用部分水合时,你需要在初始水合期间提供一个 HydrateFallback 组件进行渲染。此外,如果你之前使用 fallbackElement,你需要将其移除,因为它现在已被弃用。在大多数情况下,你会希望将 fallbackElement 复用为 HydrateFallback

👉 fallbackElement 替换为 HydrateFallback

const router = createBrowserRouter(
  [
    {
      path: "/",
      Component: Layout,
+      HydrateFallback: Fallback,
      // or
+      hydrateFallbackElement: <Fallback />,
      children: [],
    },
  ],
);


<RouterProvider
  router={router}
-  fallbackElement={<Fallback />}
/>

v7_skipActionErrorRevalidation

如果你没有使用 createBrowserRouter,可以跳过此项。

启用此 Flag 后,当 action 抛出/返回带有 4xx/5xx 状态码的 Response 时,loaders 默认将不再重新验证(revalidate)。在这些情况下,你可以通过 shouldRevalidateactionStatus 参数选择进行重新验证。

👉 启用该 Flag

createBrowserRouter(routes, {
  future: {
    v7_skipActionErrorRevalidation: true,
  },
});

更新您的代码

在大多数情况下,你可能不需要修改你的应用代码。通常,如果 action 出错,数据不太可能被修改,因此无需重新验证。如果你的任何代码*确实*在 action 错误场景下修改了数据,你有 2 个选项:

👉 选项 1:修改 action,避免在错误场景下进行数据修改

// Before
async function action() {
  await mutateSomeData();
  if (detectError()) {
    throw new Response(error, { status: 400 });
  }
  await mutateOtherData();
  // ...
}

// After
async function action() {
  if (detectError()) {
    throw new Response(error, { status: 400 });
  }
  // All data is now mutated after validations
  await mutateSomeData();
  await mutateOtherData();
  // ...
}

👉 选项 2:通过 shouldRevalidateactionStatus 选择进行重新验证

async function action() {
  await mutateSomeData();
  if (detectError()) {
    throw new Response(error, { status: 400 });
  }
  await mutateOtherData();
}

async function loader() { ... }

function shouldRevalidate({ actionStatus, defaultShouldRevalidate }) {
  if (actionStatus != null && actionStatus >= 400) {
    // Revalidate this loader when actions return a 4xx/5xx status
    return true;
  }
  return defaultShouldRevalidate;
}

弃用项

jsondefer 方法已被弃用,推荐改为返回原始对象。

async function loader() {
- return json({ data });
+ return { data };

如果你之前使用 json 将数据序列化为 JSON,现在可以使用原生的 Response.json() 方法。

升级到 v7

现在你的应用已经准备就绪,理论上你可以轻松更新到 v7,应该不会有问题。

👉 安装 v7

npm install react-router-dom@latest

👉 用 react-router 替换 react-router-dom

在 v7 中,我们不再需要 "react-router-dom",因为包已经简化。你可以从 "react-router" 中导入所有内容。

npm uninstall react-router-dom
npm install react-router@latest

请注意,你的 package.json 中只需要 "react-router"

👉 更新导入

现在你应该更新你的导入,使用 react-router

-import { useLocation } from "react-router-dom";
+import { useLocation } from "react-router";

除了手动更新导入外,你还可以使用此命令。不过请确保你的 Git 工作区是干净的,这样如果它没有按预期工作,你可以回退。

find ./path/to/src \( -name "*.tsx" -o -name "*.ts" -o -name "*.js" -o -name "*.jsx" \) -type f -exec sed -i '' 's|from "react-router-dom"|from "react-router"|g' {} +

如果你安装了 GNU sed(大多数 Linux 发行版都有),请使用此命令:

find ./path/to/src \( -name "*.tsx" -o -name "*.ts" -o -name "*.js" -o -name "*.jsx" \) -type f -exec sed -i 's|from "react-router-dom"|from "react-router"|g' {} +

👉 更新 DOM 特定的导入

RouterProviderHydratedRouter 来自一个深度导入(deep import),因为它们依赖于 "react-dom"

-import { RouterProvider } from "react-router-dom";
+import { RouterProvider } from "react-router/dom";

请注意,对于非 DOM 上下文(例如 Jest 测试),你应该使用顶级导入(top-level import)。

-import { RouterProvider } from "react-router-dom";
+import { RouterProvider } from "react-router";

恭喜,你现在已经升级到 v7 了!

文档和示例 CC 4.0