useFetcherを使ったページ遷移なしのサーバーアクション実行
Remixの`useFetcher`フックを使えば、ページ遷移なしでサーバーアクションを実行できます。検索機能やニュースレター登録など、ユーザー体験を損なわずにサーバーサイド処理を行いたい場合に最適です。
広告ここから
広告ここまで
目次
Remixでは、フォームの送信やデータの取得時に、通常は<Form>コンポーネントやuseSubmitを使用してページ遷移を伴うアクションを実行します。しかし、検索機能やニュースレター登録フォームなど、ページ遷移を伴わずにサーバーサイドの処理を実行したい場合があります。このような場合に便利なのがuseFetcherフックです。
使用例
useFetcherを利用することで、ページ遷移なしでサーバーサイドのアクションなどを呼び出せるようになります。ポイントとしては、アクションを呼び出す際のformコンポーネントを、useFetcherで取得できるFormコンポーネントで実装することです。
function SearchComponent() {
  const fetcher = useFetcher();
  return (
    <div>
      <fetcher.Form method="post" action="/api/search">
        <input type="text" name="query" />
        <button type="submit">検索</button>
      </fetcher.Form>
      {fetcher.state === "submitting" && <p>検索中...</p>}
      {fetcher.data && (
        <ul>
          {fetcher.data.results.map(result => (
            <li key={result.id}>{result.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
}
アクション側の実装
useFetcherを使用する際のサーバーサイドの実装は、通常のRemixのアクションと同じ方法で書くことができます。検索フォームの実装であれば、たとえばこのような実装になります。
// app/routes/api.search.tsx
import { ActionFunctionArgs } from "@remix-run/node";
export async function action({ request }: ActionFunctionArgs) {
  // フォームデータの取得
  const formData = await request.formData();
  const query = formData.get("query");
  // バリデーション
  if (!query || typeof query !== "string") {
    return Response.json(
      { error: "検索クエリは必須です" },
      { status: 400 }
    );
  }
  try {
    // 検索ロジックの実行
    const results = await searchDatabase(query);
    // 結果の返却
    return Response.json({ results });
  } catch (error) {
    return Response.json(
      { error: "検索中にエラーが発生しました" },
      { status: 500 }
    );
  }
}
useFetcherによる状態管理
これを利用している場合、fetcher.stateで現在の状態を確認できます。以下の3つのステータスを、コンポーネント側でハンドルしましょう。
idle: 何も実行していないsubmitting: フォームを送信中loading: アクション完了後、ページのローダーを再実行中