Help us understand the problem. What is going on with this article?

React.useEffectで非同期処理をする場合の注意点2つ

More than 1 year has passed since last update.

はじめに

React 16.8から導入されたhooksにはuseEffectがあります。

詳細は公式サイトをまず参照しましょう。

useEffectを使うと、コンポーネントのレンダリングとは別に処理を書くことができます。useEffectでしばしば非同期処理を書くことがあります。例えば、サーバからのデータ取得の処理などがあります。

以下では、useEffectで非同期処理を書く場合の注意点を2つ紹介します。ケースによっては注意点はこの2つだけではない可能性が高いので、ご留意ください。

promiseを返さない

useEffectに渡す関数の戻り値はcleanup関数です。

useEffect(() => {
  console.log('side effect!');
  const cleanup = () => {
    console.log('cleanup!');
  };
  return cleanup;
}, []);

cleanup関数は次のeffectが呼ばれる前やアンマウントする場合に呼ばれます。(depsが[]なのでこの例では後者のみ)

よって、下記は間違いです。

useEffect(async () => {
  await new Promise(r => setTimeout(r, 1000));
  console.log('side effect!');
}, []);

このコードはcleanup関数の代わりにpromiseを返してしまっています。
正しくは、下記のようにします。

const sleep = ms => new Promise(r => setTimeout(r, ms));

useEffect(() => {
  const f = async () => {
    await new Promise(r => setTimeout(r, 1000));
    console.log('side effect!');
  };
  f();
}, []);

アンマウントのフラグを持つ

非同期処理を書く場合、コンポーネントが削除された後にコールバックが呼ばれる場合があります。この時、コンポーネントのステートを変更しようとするとワーニングがでます。

const [count, setCount] = useState(0);
useEffect(() => {
  const f = async () => {
    await new Promise(r => setTimeout(r, 1000));
    setCount(c => c + 1);
  };
  f();
}, []);

これを回避するには次のようにアンマウントのフラグを持ちます。

const [count, setCount] = useState(0);
useEffect(() => {
  let unmounted = false;
  const f = async () => {
    await new Promise(r => setTimeout(r, 1000));
    if (!unmounted) {
      setCount(c => c + 1);
    }
  };
  f();
  const cleanup = () => {
    unmounted = true;
  };
  return cleanup;
}, []);

おわりに

React HooksのuseEffectについて非同期処理を使う場合のよくあるケースの注意点について紹介しました。React Hooksはまだベストプラクティスが溜まっていないため、今後違う方法が主流になる可能性はある点についてはご注意ください。

informetis
電力分野でイノベーションを目指す技術集団です。
https://www.informetis.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした