データローディング
このページの内容

データ読み込み

データは、loaderclientLoaderからルートコンポーネントに提供されます。

ローダーデータは、ローダーから自動的にシリアライズされ、コンポーネントでデシリアライズされます。文字列や数値のようなプリミティブ値に加えて、ローダーはPromise、Map、Set、日付などを返すことができます。

クライアントデータ読み込み

clientLoaderは、クライアントでデータをフェッチするために使用されます。これは、ブラウザからのみデータをフェッチしたいページやプロジェクト全体で役立ちます。

// route("products/:pid", "./product.tsx");
import type { Route } from "./+types/product";

export async function clientLoader({
  params,
}: Route.ClientLoaderArgs) {
  const res = await fetch(`/api/products/${params.pid}`);
  const product = await res.json();
  return product;
}

export default function Product({
  loaderData,
}: Route.ComponentProps) {
  const { name, description } = loaderData;
  return (
    <div>
      <h1>{name}</h1>
      <p>{description}</p>
    </div>
  );
}

サーバーデータ読み込み

サーバーレンダリングの場合、loaderは初期ページロードとクライアントナビゲーションの両方に使用されます。クライアントナビゲーションは、React Routerによるブラウザからサーバーへの自動的なfetchを通じてローダーを呼び出します。

// route("products/:pid", "./product.tsx");
import type { Route } from "./+types/product";
import { fakeDb } from "../db";

export async function loader({ params }: Route.LoaderArgs) {
  const product = await fakeDb.getProduct(params.pid);
  return product;
}

export default function Product({
  loaderData,
}: Route.ComponentProps) {
  const { name, description } = loaderData;
  return (
    <div>
      <h1>{name}</h1>
      <p>{description}</p>
    </div>
  );
}

loader関数はクライアントバンドルから削除されるため、ブラウザに含めることを心配せずにサーバーのみのAPIを使用できることに注意してください。

静的データ読み込み

プリレンダリング時、ローダーはプロダクションビルド中にデータをフェッチするために使用されます。

// route("products/:pid", "./product.tsx");
import type { Route } from "./+types/product";

export async function loader({ params }: Route.LoaderArgs) {
  let product = await getProductFromCSVFile(params.pid);
  return product;
}

export default function Product({
  loaderData,
}: Route.ComponentProps) {
  const { name, description } = loaderData;
  return (
    <div>
      <h1>{name}</h1>
      <p>{description}</p>
    </div>
  );
}

プリレンダリングするURLはreact-router.config.tsで指定します。

import type { Config } from "@react-router/dev/config";

export default {
  async prerender() {
    let products = await readProductsFromCSVFile();
    return products.map(
      (product) => `/products/${product.id}`
    );
  },
} satisfies Config;

サーバーレンダリング時には、プリレンダリングされていないURLは通常どおりサーバーレンダリングされます。これにより、残りをサーバーレンダリングしながら、単一のルートで一部のデータをプリレンダリングできます。

両方のローダーを使用する

loaderclientLoaderは一緒に使用できます。loaderは初期SSR(またはプリレンダリング)のためにサーバーで使用され、clientLoaderは後続のクライアントサイドナビゲーションで使用されます。

// route("products/:pid", "./product.tsx");
import type { Route } from "./+types/product";
import { fakeDb } from "../db";

export async function loader({ params }: Route.LoaderArgs) {
  return fakeDb.getProduct(params.pid);
}

export async function clientLoader({
  params,
}: Route.ClientLoader) {
  const res = await fetch(`/api/products/${params.pid}`);
  return res.json();
}

export default function Product({
  loaderData,
}: Route.ComponentProps) {
  const { name, description } = loaderData;

  return (
    <div>
      <h1>{name}</h1>
      <p>{description}</p>
    </div>
  );
}

次へ: アクション

関連情報

ドキュメントと例 CC 4.0