発行:

データローディング (Loader)

これまでReactでは、データ取得に useEffect フックを使うのが一般的でした。
しかし、現在のReact Routerでは、ルーティングとデータ取得を統合した Loader という機能が提供されています。

これにより、「ページが表示されてからデータを読み込み始める(Loadingスピナーが出る)」のではなく、「データを読み込んでからページを表示する」といった高度な最適化が可能になります。

Loaderの定義

Loaderは、単なる非同期関数であり、コンポーネントの外(ファイルレベル)で定義するのがベストプラクティスです。

ローダー関数の構成

この関数は、URLパラメータ(:postId など)を含む params オブジェクトを受け取ることができます。

src/PostDetail.jsx
import { useLoaderData } from "react-router-dom";

// 1. ローダー関数を定義(コンポーネントの外に置く)
export const postDetailLoader = async ({ params }) => {
  const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.postId}`);

  if (!response.ok) {
    // ここでエラーを投げると、後述の errorElement が反応する
    throw new Error("記事が見つかりませんでした");
  }

  return response.json();
};

useLoaderDataによるデータの受取

コンポーネント内では、useLoaderData フックを使って、ローダーが返したデータを直接受け取ります。

const PostDetail = () => {
  const post = useLoaderData(); // 型安全にデータを受け取れる

  return (
    <article className="p-8">
      <h1 className="text-3xl font-black">{post.title}</h1>
      <p className="mt-6 leading-relaxed text-slate-400">{post.body}</p>
    </article>
  );
};

ルートへの紐付け

定義した loader を、ルーティング設定(createBrowserRouter)に登録します。

ルート定義の更新

パスごとに loader プロパティを指定することで、そのパスに遷移した際に自動的にデータフェッチが走るようになります。

src/main.jsx
const router = createBrowserRouter([
  {
    path: "posts/:postId",
    element: <PostDetail />,
    loader: postDetailLoader, // ローダーを登録
    errorElement: <ErrorPage />, // エラー発生時のフォールバック
  },
]);

errorElementによる宣言的エラーハンドリング

Loader内でエラーが発生した場合、React Routerは element の代わりに errorElement を表示します。これにより、各コンポーネントに if (error) return ... といったボイラープレートを書く必要がなくなります。

Loaderの革新的なメリット

  1. ウォーターフォール問題の解消 : ネストされたルートがある場合、親と子のデータを 並列 に取得しに行けます。
  2. 宣言的な状態管理 : 「読み込み中」「エラー」「成功」の状態管理をライブラリ側に任せることができます。
  3. UXの向上 : データが揃うまで遷移を待機(またはSuspenseで表示)させることができるため、ページのチラつきを抑えられます。