🍣

useEffect内での不要なstate更新を避ける

2023/12/11に公開

最初に

Reactの公式ドキュメントを読んでいて、誤ったuseEffectの使い方をしていることを学んだので、記録します。

前提

Reactは、stateを更新するとコンポーネントを再レンダリングした後に、useEffectを実行する。
そのため、useEffectでstateを更新してしまうと、せっかくstateを更新した後に再度useEffectでも更新されてしまい、パフォーマンスが低下してしまう上に思わぬ不具合につながる。
なので、既存のpropsやstateから計算できるものはstateに入れず、レンダー中に計算するべき。

よくない例

function Form() {
  const [firstName, setFirstName] = useState('Taylor');
  const [lastName, setLastName] = useState('Swift');
  const [fullName, setFullName] = useState('');

useEffect(() => {
    setFullName(firstName + ' ' + lastName);
  }, [firstName, lastName]);
  // ...
}

この処理の流れは以下

  1. firstName, lastNameのstateが更新される
  2. 新しいfirstName, lastNameの値でコンポーネントが再レンダリングされる。この時点でfullNameは古いまま(fullNameを書き換えるコードはuseEffect内にしかないが、まだuseEffectは実行されていないため)
  3. useEffectが実行され、fullNameのstateが更新される。これにより新しいfullNameの値で再レンダリングされる
  4. firstName, lastNameが更新されていないのでuseEffectは実行されない

2回レンダリングされてしまっている。なので以下のようにする

いい例

function Form() {
  const [firstName, setFirstName] = useState('Taylor');
  const [lastName, setLastName] = useState('Swift');
  const fullName = firstName + ' ' + lastName;
  // ...
}

こうすれば処理の流れが以下になる

  1. firstName, lastNameのstateが更新される
  2. 新しいfirstName, lastNameの値でコンポーネントが再レンダリングされる。その時にfullNameも新しい値になる

レンダリング回数が1回だけになり、無駄がなくなりました!

最後に

他にもよく無い使い方をしてしまっている(確信)ので、正しい使い方を学んでいきます!

参考

Discussion