LoginSignup
30
19

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-06-26

はじめに

前ステップから続き、勉強用のuseFetchを書いていきます。

課題

ステップ1のコードを使うと、次のようなワーニングが出る場合があります。

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

破棄されたコンポーネントに対して更新処理をしようとして怒られています。このワーニングを意図的に出すには、useFetchを使っているコンポーネントにkeyプロパティを設定して、それを変更します。1秒以内に破棄されると、その後setResultを実行するところでワーニングとなります。

ステップ2: cleaned-upフラグ

const useFetch = url => {
  const [result, setResult] = useState({});
  useEffect(() => {
    let cleanedUp = false;
    const fetchData = async () => {
      const response = await fetch(url);
      const data = await response.json();
      if (!cleanedUp) {
        setResult({ data });
      }
    };
    fetchData();
    const cleanup = () => {
      cleanedUp = true;
    };
    return cleanup;
  }, [url]);
  return result;
};

ステップ1からの差分はcleanupの処理が入ったことです。useEffectで非同期処理を扱う場合はほぼ例外なくcleanup処理を入れることが必須です。今回のケースでは、単純にcleanedUpフラグを用意してcleanup後にsetResultを実行しないようにしました。 参考 1

このフラグによる処理の中断を「キャンセル」と読んでいる記事をたまに見かけますが、これは非同期処理のキャンセルとは呼べるものではないので注意してください。

動作確認

実際に動くコードはこちらです。codesandbox

おわりに

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


  1. 過去の記事では「アンマウントのフラグ」と書いていましたが、関数コンポーネントにおいてマウント・アンマウントという表現を使うのは正しくない気がするので、「破壊」とか「クリーンアップ」と呼ぶようにしてみようかと思います。ただ、この呼び方もより良いものが見つかれば変えるので、定着したものではありません。 

30
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
19