v6からのアップグレード

すべての将来のフラグを有効にしている場合、v7へのアップグレードには破壊的な変更はありません。これらのフラグを使用すると、アプリを一度に1つの変更ずつ更新できます。一度にすべてを行うのではなく、各ステップの後でコミットしてデプロイすることを強くお勧めします。

最新のv6.xにアップデート

まず、最新の将来のフラグとコンソール警告を取得するために、v6.xの最新のマイナーバージョンにアップデートします。

👉 最新のv6にアップデート

npm install react-router-dom@6

v7_relativeSplatPath

背景

dashboard/*のような複数セグメントのスプラットパス(単なる*に対して)の相対パスのマッチングとリンクを変更します。詳細はCHANGELOGをご覧ください。

👉 フラグを有効にする

フラグの有効化は、ルーターの種類によって異なります。

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

コードを更新する

<Route path="dashboard/*">のようなパスとスプラットを持つルートで、その下に<Link to="relative">または<Link to="../relative">のような相対リンクがある場合、コードを更新する必要があります。

👉 <Route>を2つに分割する

複数セグメントのスプラット<Route>を、パスを持つ親ルートとスプラットを持つ子ルートに分割します。

<Routes>
  <Route path="/" element={<Home />} />
-  <Route path="dashboard/*" element={<Dashboard />} />
+  <Route path="dashboard">
+    <Route path="*" element={<Dashboard />} />
+  </Route>
</Routes>
 
// または
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.useStateの代わりにReact.useTransitionを使用します。詳細はCHANGELOGをご覧ください。

👉 フラグを有効にする

<BrowserRouter
  future={{
    v7_startTransition: true,
  }}
/>
 
// または
<RouterProvider
  future={{
    v7_startTransition: true,
  }}
/>

👉 コードを更新する

コンポーネント内でReact.lazyを使用していない限り、何も更新する必要はありません。

コンポーネント内でReact.lazyを使用することは、React.useTransition(またはコンポーネント内でPromiseを作成するその他のコード)と互換性がありません。React.lazyをモジュールスコープに移動し、コンポーネント内でPromiseを作成することを停止します。これはReact Routerの制限ではなく、Reactの誤った使用方法です。

v7_fetcherPersist

<RouterProvider>を使用していない場合は、これをスキップできます

背景

フェッチャーのライフサイクルは、所有者コンポーネントがアンマウントされるときではなく、アイドル状態に戻るときに基づいています。詳細はCHANGELOGをご覧ください。

フラグを有効にする

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

コードを更新する

アプリに影響を与える可能性は低いでしょう。useFetchersの使用状況を確認したい場合があるかもしれません。それらは以前よりも長く持続する可能性があります。何をしているかによっては、以前よりも長く何かをレンダリングする可能性があります。

v7_normalizeFormMethod

<RouterProvider>を使用していない場合は、これをスキップできます

これはformMethodフィールドを大文字のHTTPメソッドに正規化して、fetch()の動作と一致させます。詳細はCHANGELOGをご覧ください。

👉 フラグを有効にする

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>を使用していない場合は、これをスキップできます

これにより、SSRフレームワークは部分的なハイドレーションデータのみを提供できます。これについて心配する必要はほとんどなく、フラグをオンにするだけです。詳細はCHANGELOGをご覧ください。

👉 フラグを有効にする

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

コードを更新する

部分的なハイドレーションでは、初期ハイドレーション中にレンダリングするHydrateFallbackコンポーネントを提供する必要があります。さらに、以前にfallbackElementを使用していた場合は、非推奨になったため削除する必要があります。ほとんどの場合、fallbackElementHydrateFallbackとして再利用したいでしょう。

👉 fallbackElementHydrateFallbackに置き換える

const router = createBrowserRouter(
  [
    {
      path: "/",
      Component: Layout,
+      HydrateFallback: Fallback,
      // または
+      hydrateFallbackElement: <Fallback />,
      children: [],
    },
  ],
);
 
 
<RouterProvider
  router={router}
-  fallbackElement={<Fallback />}
/>

v7_skipActionErrorRevalidation

createBrowserRouterを使用していない場合は、これをスキップできます

このフラグが有効になっている場合、ローダーは、アクションが4xx/5xxステータスコードのResponseをスロー/返した後、デフォルトでは再検証されなくなります。これらのシナリオでは、shouldRevalidateactionStatusパラメーターを介して再検証を選択できます。

👉 フラグを有効にする

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

コードを更新する

ほとんどの場合、アプリのコードを変更する必要はないでしょう。通常、アクションでエラーが発生した場合、データが変更され、再検証が必要になる可能性は低いでしょう。コードがアクションエラーのシナリオでデータを変更する場合は、2つのオプションがあります。

👉 オプション1:エラーシナリオでの変更を回避するためにactionを変更する

// 前
async function action() {
  await mutateSomeData();
  if (detectError()) {
    throw new Response(error, { status: 400 });
  }
  await mutateOtherData();
  // ...
}
 
// 後
async function action() {
  if (detectError()) {
    throw new Response(error, { status: 400 });
  }
  // すべてのデータは検証後に変更されます
  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) {
    // アクションが4xx/5xxステータスを返す場合、このローダーを再検証します
    return true;
  }
  return defaultShouldRevalidate;
}

v7にアップグレード

アプリが最新の状態になったら、問題なくv7にアップデートできます(理論的には!)。

👉 v7をインストール

npm install react-router-dom@latest

👉 react-router-domreact-routerに置き換える

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' {} +

👉 DOM固有のインポートを更新する

RouterProviderHydratedRouterは、"react-dom"に依存しているため、深いインポートから取得されます。

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

おめでとうございます。これでv7になりました!