🐇

Remix Loader の発火原因を見極める

2024/07/26に公開

はじめに

Remix アプリを開発している際に Loader の発火理由を判定する必要がありました。リンクをクリックした場合と useFetcher を使用した場合で Loader 内の処理を少し変える必要があったためです。

この記事では、試行錯誤の末に見つけた Remix Loader の発火理由を判定する方法を紹介します。

Remix Loader が発火するタイミング

Loaderが発火するタイミングは、主に以下の3つのシチュエーションに分けられます。

  1. ページの初回読み込み

    • URL を直接入力してアクセスしたときや、ブラウザのリロードが行われたときに、初回のサーバーリクエストが発生し Loader が発火します。
  2. 内部リンク

    • Remix の Link コンポーネントや navigate 関数を使用して、別のページに遷移したときに Loader が発火します。
  3. useFetcher の使用

    • Remix の useFetcher フックを使用してデータ取得を行ったとき、指定したセグメントの Loader が発火します。

ページの初回読み込みか判定する方法

export function loader({ request }: LoaderFunctionArgs) {
  const dest = request.headers.get('Sec-Fetch-Dest');
  if (dest === 'document') {
    // ここに入ってきたらページの初回読み込み
  }

  return { message: 'Hello from the loader!' };
}

HTTP ヘッダーの Sec-Fetch-User を利用することで判定が可能です。値が document であれば、ページの初回読み込みとなります。
remix-utils というライブラリの fetchDest を利用すると、より簡単に Sec-Fetch-User の値が取得できそうです。

内部リンクと useFetcher 使用を判定する方法

export function loader({ request }: LoaderFunctionArgs) {
  const url = new URL(request.url);
  const from = url.searchParams.get('from') ?? undefined;
  if (dest === 'fetcher') {
    // ここに入ってきたら useFetcher を使用しようした読み込み
  }

  return { message: 'Hello from the loader!' };
}

export default function Index() {
  const fetcher = useFetcher();

  const handleClick = () => {
    if (fetcher.state === 'idle') {
      fetcher.load('/xxxxxxxx&from=fetcher');
    }
  };

  return <button onClick={handleClick}>fetch!</button>;
}

URLSearchParams を利用することで判定が可能です。useFetcher 使用する場合は、fetcher.load に指定するエンドポイントを URLSearchParams のフラグ付きにすることで、内部リンクと useFetcher 使用を判定することができます。

本当は、「ページの初回読み込みか判定する方法」と同じように HTTP ヘッダーなどから判定できたら良かったのですが難しそうです。理由は、Remix の Link コンポーネントや navigate で遷移をした場合は、内部的には fetcher.load で遷移先ページの loader が実行され、React Router によって画面が作られるからです。また fetcher.load では、カスタムヘッダーの追加も許されていないです。

Discussion