🏃
Remix v2 から React Router v7 への移行情報まとめ(2025年1月時点)
以下はRemix v2からReact Router v7への移行を検討にするに際してまとめた情報です。
1. 背景と概要
- React Router v7 は 2024 年 11 月 22 日にリリースされ、Remix v2 の機能を統合
- もともと Remix は React Router をベースにしたフルスタックフレームワーク
- 「Remix v3」として予定されていた機能が「React Router v7」として提供
- React Router v7 はルーティングライブラリからフルスタックフレームワークへ進化
2. 主な変更点
2.1 ルーティング方式
コンフィグベースルーティング
// app/routes.ts
import {
type RouteConfig,
route,
index,
layout,
} from "@react-router/dev/routes";
export const routes: RouteConfig = [
index("./home.tsx"),
route("about", "./about.tsx"),
layout("./auth/layout.tsx", [
route("login", "./auth/login.tsx"),
route("register", "./auth/register.tsx"),
]),
];
ファイルベースルーティング
- @react-router/fs-routes を使用して Remix v2 同様のファイルベースルーティングも可能
import { flatRoutes } from "@react-router/fs-routes";
export default flatRoutes() satisfies RouteConfig;
2.2 型安全性の向上
- ルートごとの型が自動生成される
- useLoaderData や useActionData の型補完が改善
- パスパラメータやクエリパラメータの型定義が可能
2.3 API の変更
- Remix の API が react-router に統合
- json() や defer() などの一部 API は削除
- エントリーポイントのコンポーネントが変更
- RemixServer → ServerRouter
- RemixBrowser → HydratedRouter
3. 移行手順
- Future Flags の有効化
// vite.config.ts
remix({
future: {
v3_fetcherPersist: true,
v3_relativeSplatPath: true,
v3_throwAbortReason: true,
v3_singleFetch: true,
v3_lazyRouteDiscovery: true,
},
});
- 依存パッケージの更新
- @remix-run/_ → @react-router/_ に置換
- codemod を使用して自動更新可能:
npx codemod remix/2/react-router/upgrade
- package.json の scripts 更新
- "dev": "remix vite:dev"
+ "dev": "react-router dev"
- "build": "remix vite:build"
+ "build": "react-router build"
- routes.ts ファイルの追加
- コンフィグベースまたはファイルベースのルーティング設定
- react-router.config.ts の追加
import type { Config } from "@react-router/dev/config";
export default {
ssr: true,
} satisfies Config;
- Vite プラグインの更新
- import { vitePlugin as remix } from "@remix-run/dev";
+ import { reactRouter } from "@react-router/dev/vite";
export default defineConfig({
plugins: [
- remix(),
+ reactRouter(),
],
});
- 型生成の設定
// tsconfig.json
{
"include": [
+ ".react-router/types/**/*"
],
"compilerOptions": {
- "types": ["@remix-run/node", "vite/client"],
+ "types": ["@react-router/node", "vite/client"],
+ "rootDirs": [".", "./.react-router/types"]
}
}
4. 開発体験の向上
4.1 型安全性の強化
-
自動型生成
- ルートパラメータの型が自動生成され、パスパラメータの typo を防止
- loader や action の戻り値の型が自動的に推論され、コンポーネントでの型エラーを防止
- クエリパラメータの型安全性も向上
-
loader 関数の型定義の改善
// Remix v2 での型定義 export const loader: LoaderFunction = async ({ params }) => { const data = await fetchData(params.id); // params.id の型が不明確 return json(data); // 戻り値の型も不明確 }; // React Router v7 での型定義 import type { Route } from "./+types/product"; export async function loader({ params }: Route.LoaderArgs) { const data = await fetchData(params.id); // params.id が string型と推論される return data; // 戻り値の型が自動的に推論される } // コンポーネントでの型安全な利用 export default function Product({ loaderData }: Route.ComponentProps) { // loaderDataの型が自動的に推論される const { name, description } = loaderData; return ( <div> <h1>{name}</h1> <p>{description}</p> </div> ); }
- 関数のオーバーロードサポート
// 複数の戻り値パターンを型安全に定義 export async function loader({ params }: Route.LoaderArgs): Promise<Product>; export async function loader({ params }: Route.LoaderArgs) { if (params.id === "special") { return redirect("/special-products"); } const product = await getProduct(params.id); return product; }
- loader や action で複数の戻り値パターンを型安全に定義可能
- リダイレクトとデータ返却の両方を扱うケースでも型の整合性を保証
4.2 開発効率の向上
-
コード分割の最適化
- ルートごとの自動的なコード分割
- 必要なモジュールのみを効率的にロード
-
データフェッチの改善
- loader/action の実行結果が自動的に再検証
- 楽観的 UI の実装が容易に
- Suspense と組み合わせた効率的なローディング制御
4.3 Web 標準への準拠
-
標準 API の活用
- Response/Request API の直接利用
- Web Streams を使用した SSR の最適化
- FormData や URLSearchParams の活用
5. 移行の判断基準
移行を推奨するケース:
- React 19 への対応を予定している
- 型安全性の向上を求めている
- フルスタック機能を活用したい
待機を検討するケース:
- RSC 対応版のリリースを待ちたい
- 現行の Remix v2 で問題ない
- 大規模な移行リソースが確保できない
6. まとめ
- codemod を活用することで比較的スムーズな移行が可能
- React 19 対応を見据えた場合は移行が推奨
- 型安全性が向上し、開発体験が改善
- Remix の機能を継承しつつ、より統合された開発体験を提供
- Web 標準に準拠した API で、より直感的な開発が可能に
- 型安全性の強化により、開発時のエラーを早期に発見可能
Discussion