[勉強用] React hooksで非同期処理を書く (ステップ5)


はじめに

前ステップから続き、勉強用のuseFetchを書いていきます。今回のテーマはキャンセル処理です。

課題

URLを変更すると、クリーンアップ処理が走り、新しいデータ取得が走りますが、ブラウザが処理をしている前のデータ取得の処理を止めることができたわけではありません。例えば、長いデータを転送中だったり、サーバからの応答を待っていたり、サーバの名前解決をしていたりする場合は、データ取得の処理は継続しています。fetchはpromiseベースのAPIですが、AbortControllerを使うことで処理をキャンセル(abort)することができます。

ステップ5: キャンセル処理

const useFetch = url => {
  const [result, setResult] = useState({});
  useEffect(() => {
    let cleanedUp = false;
    const abortController = new AbortController();
    const fetchData = async () => {
      try {
        const response = await fetch(url, {
          signal: abortController.signal
        });
        if (!response.ok) throw new Error(`status: ${response.status}`);
        const data = await response.json();
        if (!cleanedUp) {
          setResult({ data });
        }
      } catch (error) {
        if (!cleanedUp) {
          setResult({ error });
        }
      }
    };
    setResult({ loading: true });
    fetchData();
    const cleanup = () => {
      cleanedUp = true;
      abortController.abort();
      setResult({});
    };
    return cleanup;
  }, [url]);
  return result;
};

念のため、cleanupでresultも初期化するようにしました。(一瞬以前のresultで描画されるを防ぐため)

動作確認

実際に動くコードはこちらです。codesandbox
キャンセルの動作はUIで直接は分かりませんので、Chrome DevToolsでNetworkタブを確認してください。

このように、ローディング中にURLを変更すると、canceledとなっていることを確認できると思います。

おわりに

本コードは勉強用ですので、そのままでは使わないでください。(ちゃんとした実装はこちら)
さらなる課題と解決は次のステップへ。