すべてのfutureフラグを有効にしていれば、v7へのアップグレードに破壊的な変更はありません。これらのフラグにより、アプリを一度に1つずつ変更して更新できます。すべてを一度に行うのではなく、各手順の後にコミットして出荷することを強くお勧めします。
まず、最新のfutureフラグとコンソール警告を取得するために、v6.xの最新のマイナーバージョンに更新します。
👉 **最新v6へのアップデート**
npm install react-router-dom@6
背景
dashboard/*
(単なる*
ではなく)のような複数セグメントのスプラットパスの相対パス照合とリンクを変更します。詳細については、変更履歴をご覧ください。
👉 **フラグを有効にする**
フラグの有効化は、ルーターの種類によって異なります
<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>
// 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>
);
}
背景
これは、ルーターの状態更新にReact.useState
の代わりにReact.useTransition
を使用します。詳細については、変更履歴をご覧ください。
👉 **フラグを有効にする**
<BrowserRouter
future={{
v7_startTransition: true,
}}
/>
// or
<RouterProvider
future={{
v7_startTransition: true,
}}
/>
👉 **コードの更新**
コンポーネントの*内部*でReact.lazy
を使用していない限り、何も更新する必要はありません。
コンポーネント内部でReact.lazy
を使用することは、React.useTransition
(またはコンポーネント内部でPromiseを作成する他のコード)と互換性がありません。React.lazy
をモジュールスコープに移動し、コンポーネント内部でPromiseを作成しないようにしてください。これはReact Routerの制限ではなく、Reactの誤った使用方法です。
<RouterProvider>
を使用していない場合は、これをスキップできます
背景
フェッチャーのライフサイクルは、所有者コンポーネントがアンマウントされたときではなく、アイドル状態に戻ったときに基づくようになりました。詳細については、変更履歴をご覧ください。
フラグを有効にする
createBrowserRouter(routes, {
future: {
v7_fetcherPersist: true,
},
});
コードの更新
アプリに影響を与える可能性は低いです。useFetchers
の使用状況を確認すると、以前よりも長く存続する可能性があります。何をしているかによっては、以前よりも長くレンダリングされる場合があります。
<RouterProvider>
を使用していない場合は、これをスキップできます
これは、fetch()
の動作に合わせて、formMethod
フィールドを大文字のHTTPメソッドとして正規化します。詳細については、変更履歴をご覧ください。
👉 **フラグを有効にする**
createBrowserRouter(routes, {
future: {
v7_normalizeFormMethod: true,
},
});
コードの更新
コードで小文字のHTTPメソッドを確認している場合は、大文字のHTTPメソッドを確認するように更新する必要があります(または、toLowerCase()
を呼び出します)。
👉 **formMethod
を大文字と比較する**
-useNavigation().formMethod === "post"
-useFetcher().formMethod === "get";
+useNavigation().formMethod === "POST"
+useFetcher().formMethod === "GET";
<RouterProvider>
を使用していない場合は、これをスキップできます
これにより、SSRフレームワークは部分的なハイドレーションデータのみを提供できます。これについて心配する必要はおそらくありません。フラグをオンにするだけです。詳細については、変更履歴をご覧ください。
👉 **フラグを有効にする**
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 />}
/>
createBrowserRouter
を使用していない場合は、これをスキップできます
このフラグが有効になっている場合、アクションが4xx
/5xx
ステータスコードを持つResponse
をスロー/返した後、ローダーはデフォルトで再検証されなくなります。shouldRevalidate
とactionStatus
パラメーターを使用して、これらのシナリオで再検証を選択できます。
👉 **フラグを有効にする**
createBrowserRouter(routes, {
future: {
v7_skipActionErrorRevalidation: true,
},
});
コードの更新
ほとんどの場合、アプリコードを変更する必要はおそらくありません。通常、アクションでエラーが発生した場合、データが変更されて再検証が必要になる可能性は低いです。コードのいずれかがアクションエラーシナリオでデータを*変更する*場合は、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:shouldRevalidate
とactionStatus
を介して再検証を選択する**
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;
}
json
メソッドとdefer
メソッドは、生のオブジェクトを返すことを推奨するため、非推奨になりました。
async function loader() {
- return json({ data });
+ return { data };
データをJSONにシリアル化するためにjson
を使用していた場合は、代わりにネイティブのResponse.json()メソッドを使用できます。
アプリが最新の状態になったので、問題なくv7にアップデートできます(理論的には!)。
👉 **v7をインストールする**
npm install react-router-dom@latest
👉 **react-router-domをreact-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' {} +
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固有のインポートを更新する**
RouterProvider
とHydratedRouter
は"react-dom"
に依存しているため、深いインポートから提供されます
-import { RouterProvider } from "react-router-dom";
+import { RouterProvider } from "react-router/dom";
Jestテストなどの非DOMコンテキストには、トップレベルのインポートを使用する必要があることに注意してください
-import { RouterProvider } from "react-router-dom";
+import { RouterProvider } from "react-router";
おめでとうございます。これでv7になりました!