5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React Router v7に入門してみた ~loaderで脱useEffect編~

5
Last updated at Posted at 2026-02-26

はじめに

この記事で分かること

  • React Router v7における「Dataモード」の基礎概念
  • 最小構成でのLoaderの実装方法
    • 簡単に動確できたのでこの記事ではViteベースにしてます
  • Route Objectによるネスト(入れ子)構造の作り方

想定読者

  • React Router v6以降の新機能(Data APIs)を触ってみたい方
  • useEffectでのデータ取得以外の方法でのデータ管理に触れてみたい方

なぜこの記事を書いたか

公式ドキュメントのチュートリアルをよりシンプルに分解し、Step by Stepで理解しながら実装できるようにガイドするため作成しました(多分シリーズ化します)。

Dataモードによる宣言的なデータフェッチ

React Router v7のDataモードは、従来の「useEffectによるデータ取得」ではなくloaderと呼ばれる機能でデータを取得します。

これにより、コンポーネント内の useEffectloading 状態の管理をRouterの標準機能に任せられます。

前提知識の提示

  • Reactの基礎(Props, Hooks)
  • fetch APIによる非同期通信の理解
  • 標準的な react-router-dom の利用経験

実装例:ネストされたルートとLoaderの活用

共通のナビゲーション(RootLayout)を持ちつつ、URLに応じて「一覧画面」や「詳細画面」を切り替える構成を作ります。

Loaderの作成

URLパラメータ(:userId)を受け取り、必要なデータを事前に取得する関数を定義します。

src/loaders/userDetailsLoader.ts
import { LoaderFunctionArgs } from "react-router";

export async function userDetailsLoader({ params }: LoaderFunctionArgs) {
  const response = await fetch(`https://jsonplaceholder.typicode.com/users/${params.userId}`);
  if (!response.ok) throw new Error("ユーザーが見つかりません");
  return response.json();
}

Componentの作成

useLoaderData フックを使い、Routerから渡されたデータを表示します。

src/pages/UserDetails.tsx
import { useLoaderData } from "react-router";

export default function UserDetails() {
  const user = useLoaderData() as any;

  return (
    <div>
      <h2>ユーザー詳細</h2>
      <p><strong>名前:</strong> {user.name}</p>
      <p><strong>メール:</strong> {user.email}</p>
    </div>
  );
}

Route Objectの定義(main.tsx)

createBrowserRouter 内で children を使い、親子関係を定義します。

src/main.tsx
import { createBrowserRouter, RouterProvider } from "react-router";
import RootLayout from "./layouts/RootLayout";
import App from "./App";
import UserList from "./pages/UserList";
import UserDetails from "./pages/UserDetails";
import { userLoader } from "./loaders/userLoader";
import { userDetailsLoader } from "./loaders/userDetailsLoader";

const router = createBrowserRouter([
  {
    path: "/",
    Component: RootLayout, // 親(共通レイアウト)
    children: [
      {
        index: true,
        Component: App,
      },
      {
        path: "users",
        Component: UserList,
        loader: userLoader,
      },
      {
        path: "users/:userId",
        Component: UserDetails,
        loader: userDetailsLoader,
      },
    ],
  },
]);
  • 注意点など
    • Outletの配置: 親コンポーネント(RootLayout)内に <Outlet /> を配置しないと、子ルートが表示されない
    • Loader内でのエラー: 通信エラーなどは自動的に検知されます。適切なエラー画面を表示するには errorElement の設定が推奨
      • ErrorBoundaryの話は次回以降に持ち越し

まとめ

  • Dataモードは、ページ遷移と並行してデータを取得する高速な手法
  • Loaderを定義することで、コンポーネントから「データ取得の責任」を分離し、レンダリングを最適化可能
  • Route ObjectOutletを活用すれば、共通UI(ヘッダー等)の再レンダリングを抑えつつ、動的な画面遷移が可能

続く(かも)。

参考文献

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?