0
0

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 の Loader でデータ取得をルーティングに統合する方法

Last updated at Posted at 2025-09-30

はじめに

ウェブアプリケーションでAPIからデータを取得する際、コンポーネントがレンダリングされてからデータ取得が始まると、一瞬画面が空白になる「白い画面」問題が発生します。

React RouterのLoaderは、開発時によく悩まされるデータ取得タイミングの問題を解決してくれます。
Loaderは、ページのレンダリングが始まる前に、必要なデータを準備する役割を担います。
これにより、ユーザーはローディングを待つことなく、データが完全に揃った状態のページを素早く見ることができます。

本記事では、Loaderの基本的な使い方から、データ取得、認証チェックなどの活用方法を解説します。
React Router v7を使用しています。

Loaderの役割とメリット

感覚的には、Expressなんかのミドルウェアに近いです。ページ表示の前に共通処理を挟めるので、コンポーネントがスッキリします。

Loaderの主な役割は以下の3つです。

  1. データ取得: APIから必要なデータを取得し、コンポーネントに渡します。これにより、コンポーネントはローディング状態を気にすることなく、データの表示に集中できます。

  2. 認証チェック: ユーザーがページにアクセスする前に、ログイン済みか、アクセス権限を持っているかを確認します。認証に失敗した場合は、ログインページに自動でリダイレクトします。

  3. データの前処理: APIから取得したデータを、コンポーネントに渡す前に加工したり、整形したりします。

Loaderの使い方

ルーティング定義にLoaderを追加する

Loaderは、createBrowserRouterでルーティングを定義する際に、loaderプロパティとして設定します。

// src/router.tsx
import { createBrowserRouter } from "react-router-dom";
import App from "./App.tsx";
import { userLoader } from "./loaders/userLoader.ts"; // Loaderをインポート
import ProfilePage from "./pages/ProfilePage.tsx";
import ErrorPage from "./pages/ErrorPage.tsx";

export const router = createBrowserRouter([
  {
    path: "/",
    Component: App,
    errorElement: <ErrorPage />,
    children: [
      {
        path: "profile/:userId",
        loader: userLoader, // このルートにLoaderを設定
        Component: ProfilePage,
      },
    ],
  },
]);

loader関数でデータを取得する

loader関数は、APIを呼び出してデータを取得し、そのデータをreturnします。

// src/loaders/userLoader.ts
import { redirect } from "react-router-dom";
import { getUserProfile } from "../api/userApi.ts"; // APIクライアント

export const userLoader = async ({ params }) => {
  try {
    // ユーザーIDの存在をチェック
    if (!params.userId) {
      throw new Error("ユーザーIDが見つかりません");
    }
    
    // APIからデータを取得
    const user = await getUserProfile(params.userId);
    
    // データを返却
    return user;
  } catch (error) {
    // エラーハンドリング
    console.error("ユーザーデータの取得に失敗しました", error);
    return redirect("/login");
  }
};

コンポーネントでuseLoaderDataを使う

loaderから返されたデータは、コンポーネント内でuseLoaderDataフックを使って取得できます。

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

function ProfilePage() {
  // Loaderから返されたデータを取得
  const user = useLoaderData();

  return (
    <div>
      <h1>User Profile</h1>
      <p>Name: {user.name}</p>
      <p>Email: {user.email}</p>
    </div>
  );
}

Loaderを使った認証チェック

Loaderは、ページのレンダリング前に認証状態をチェックする「認証ガード」としても使えます。

// src/loaders/checkAuth.ts
import { redirect } from "react-router-dom";
import { useAuthStore } from "../stores/authStore";

export const checkAuthLoader = () => {
  const { isAuthenticated } = useAuthStore.getState();
  
  if (!isAuthenticated) {
    // 未認証の場合はログインページにリダイレクト
    return redirect("/login");
  }
  
  return null; // 認証済みの場合は何もしない
};

このLoaderを、認証が必要なルートのloaderに設定することで、認証されていないユーザーがページにアクセスするのを防ぐことができます。

データ共有の効率化

useLoaderDataフックは、データの再取得を防ぎ、パフォーマンスを向上させるための重要な仕組みです。

loaderが返したデータは、ルーティングのメモリ上にキャッシュされます。useLoaderData()フックをコンポーネント内で何度も呼び出しても、Reactはキャッシュされた同じデータを返すため、APIへのリクエストが重複することはありません。

これにより、以下のようなメリットが得られます。

データの重複取得を防止
ProfilePageとUserStatusコンポーネントの両方でuseLoaderData()を呼び出しても、APIリクエストは1回しか行いません。

コンポーネントの再レンダリングを最適化
userPointsのような共通データをuseLoaderData()で取得することで、コンポーネントはデータの変更にのみ反応し、不要な再レンダリングを防ぎます。

おわりに

Loaderを使うようになってから、useEffectや状態管理まわりのコードがかなりスッキリしました。
毎回データ取得のたびにloading状態を気にしなくてよくなるのは、地味だけどかなり助かります。
「ルーティング」と「データの初期化処理」を同じ場所で管理できるのも、個人的には気に入ってるポイントです。
使い慣れてくると、React Routerでのデータ取得の設計がぐっと楽になります。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?