データの読み込み

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

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

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

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

app/product.tsx
// 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を通じてローダーを呼び出します。

app/product.tsx
// 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を使用できます。

静的データの読み込み

プレレンダリング時、ローダーは本番ビルド中にデータを取得するために使用されます。

app/product.tsx
// 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で指定されます。

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は後続のクライアント側のナビゲーションで使用されます。

app/product.tsx
// 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>
  );
}

次へ: アクション

参照: