useEffect 覚え書き
useEffect
について理解な曖昧な部分があったので改めて調べた。
TL;DR
useEffect
はレンダリング後に処理(副作用)するときに使う- 第2引数に依存値を設定する。
[]
と空にすると初回レンダー時のみ、第2引数自体を設定しないと毎レンダリング後に実行される - DOMの画面反映前に処理を実行したい場合は
useLayoutEffect
を使う useEffect
の返り値にはクリーンアップ関数を指定できる- クリーンアップ関数はReact17で仕様が変更され、常に次のレンダリング後のDOM状態が画面反映された後に実行されるようになった
useEffect
の基本
useEffect
は、ReactのHooksの一つで、レンダリング後に何かの処理(公式ドキュメントでは副作用と呼ばれてる)をしたいときに使う。
useEffect(() => { // 処理 }, [ hoge(依存値) ]);
レンダリング後に呼び出されるため、useEffect
が実行される際は、DOMは正しく更新されていることが保証されてる。
毎レンダリングで呼び出される必要がない場合は、第2引数に依存する値(変更があったらuseEffect
を処理したい値)を設定できる。初回レンダリング後のみで呼び出したいときは、空配列[]
を設定。
useEffect
はレンダリング後に非同期で実行されるので UX 観点では良い傾向がある。
ただ、時には同期的に処理をしたい(useEffect
を実行した後に画面に反映したい)ときがある。その時は似たHooksの useLayoutEffect
を使える。ただ、もちろんその分画面反映が遅れるのでご利用時は注意が必要。
クリーンアップ関数について
useEffect
は必須ではないが戻り値としてクリーンアップ関数を設定できる。クリーンアップ関数は自分は未だにあまり使ったことがないが、後始末的な位置付けで必要な処理のよう。
公式ドキュメントの受け売りだが、例えば、外部APIの購読に対して、クリーンアップ関数は解除をする処理を書くなど(ときには後始末をしないことでメモリリーク等が起こる可能性があり、それを防止するためにクリーンアップする)。
hooks
がない時代は、Reactのライフサイクル毎(例えば componentDidMount
と componentWillUnmount
)に書く必要があり、関連性の高いコードが分散したり、記述し忘れによるバグ発生が頻発してたらしい。
ちなみに公式ドキュメントを拝借するがコード例。
useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); // Specify how to clean up after this effect: return function cleanup() { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; });
そして、このクリーンアップ関数が、最近React17によって破壊的変更があったらしい。 詳しくは下記の記事に分かりやすくまとまっている。
要はReact17では常に次のレンダリング後のDOM状態でクリーンアップ関数が実行されるようになったとのこと。ちなみにReact16までは、アンマウント時なのか再レンダリング時なのかでDOMの状態が異なっていた。なので統一感が出て改良されたが、破壊的変更なので気をつけないとねということ。
useEffect の使い方
useEffect
は処理のタイミングを依存値によって制御することがよくあり、正しく使わないと思わぬバグや不要なレンダリングを行いパフォーマンスを損ねるケースがよくあるので注意が必要。
下記の記事が参考になった。
個人的にまとめると、
useEffect
内でしか使わない処理は関数化するにしてもuseEffect
内に入れてしまう(関数がuseEffect
の第2引数の値以外にから影響を受けないことを保証できる)- 複数の
useEffect
でpropsやstateに依存する関数を共通で呼び出す必要がある場合は、useCallback
を利用して関数を定義し、複数のuseEffect
で使うと良さそう - そもそもpropsやstateに依存しない関数はコンポーネントの外部に書く(内部に書いてもいいが副作用処理になることがほとんどなので、結局
useEffect
で依存配列を[]
に設定する感じになるので、外だしした方が無駄な処理も減り、可読性も上がる)