概要
Reactの公式ページにはエフェクトは必要ないかもしれないというページがあります。
必要のない場面でuseEffectを使うことを避けるという記事で、この記事について自分の経験や理解したことについて書こうと思います。
必要のない箇所でuseEffectを使う
useEffect自体は必要ない場面ではなるべく使わない、という知識がなかった時に自分がやってしまったアンチパターンを振り返ってみます。
自分が追加したコードで、ユーザーが入力した値をuseEffectで監視して入力値によってフォームの制御などを行う処理がありました。
これは公式の不要なエフェクトの削除方法 という項目で、以下のように書かれています。
ユーザイベントの処理にエフェクトは必要ありません。例えば、ユーザが製品を購入したときに /api/buy POST リクエストを送信し、通知を表示したいとします。購入ボタンのクリックイベントハンドラでは、何が起こったかが正確にわかります。エフェクトが実行される時点では、ユーザが何をしたのか(例えば、どのボタンがクリックされたのか)はもうわかりません。したがって、通常は対応するイベントハンドラでユーザイベントを処理するべきです。
しかし、過去の自分は既存のuseEffectに新しいdependenciesと処理を追加しました。
これをすると何が起きるのかと言うと、まず処理が追いづらかったです。イベントハンドラは直感的ですが、useEffectで項目の監視をすると、いつどんな時にdependenciesの値が変更されるのか常に意識する必要がありました。
しかも複数のdependenciesを扱っていたため、一つ処理を変えるだけでも常に複数項目を意識しなければならないため、処理が追いづらい上にバグを混入させやすいというコードになっていました。
このような経験をしていたため、エフェクトは必要ないかもしれないという公式ページを見てかなり内容に腑が落ちました。
特に
コンポーネント内の生の useEffect の呼び出しが少なければ少ないほど、アプリケーションのメンテナンスは容易になります。
という記述は、その通りと感じました。
公式が記事の内容をまとめてくれているので引用します
レンダー中に計算できるものであれば、エフェクトは必要ない。
重たい計算をキャッシュするには、useEffect の代わりに useMemo を追加する。
コンポーネントツリー全体の state をリセットするには、異なる key を渡す。
prop の変更に応じて一部の state をリセットする場合、レンダー中に行う。
複数のコンポーネントの state を更新する必要がある場合、単一のイベントで行うことが望ましい。
異なるコンポーネントの state 変数を同期しようと思った際は、常に state のリフトアップを検討する。
エフェクトでのデータフェッチは可能だが、競合状態を回避するためにクリーンアップを実装する必要がある。
hooks全般に言えることですが、いつ使うべきか、そして使わないべきかは意識した開発を行いたいですね。