React 16.8で追加されたフック (hook) 機能の一つuseEffect
について調べた
useEffect
useEffect(didUpdate);
DOM の書き換え、データの購読、タイマー、ロギング、あるいはその他の副作用をReact.renderでやるとバグや非整合性を引き起すので、レンダリングの結果が画面に反映された後に動作するようにする機能
デフォルトではレンダーが終了した後に毎回動作するが、特定の値が変化した時のみ動作させるようにすることもできる
コンポーネントが画面から消える場合にクリーンアップする必要があるようなリソース(例えば購読やタイマー ID など)をクリーンアップする用の関数を返すこともできる
useEffect(() => { const subscription = props.source.subscribe(); return () => { // Clean up the subscription subscription.unsubscribe(); }; });
タイミング
componentDidMount
や componentDidUpdate
と異なり、useEffect に渡された関数はレイアウトと描画の後で遅延されたイベントとして実行される
なるべく、この遅延処理が許容されるようにページは作られているべきだが、少なからずユーザに見えるような DOM の改変があるため、ユーザが見た目の不整合性を感じてしまい、問題になることがあるかもしれない
その場合はuseLayoutEffectというブラウザによって描画される前のタイミングで同期的に処理する機能を使う
ただし、更新がブロックされるため原則useEffectを使うようにするべき
useEffectは次回のレンダーが起こるより前に実行されることは保証されているので、たとえばページ更新頻度が激しい場合でも遅延処理による不整合は発生しない
条件付きで副作用を実行する
useEffectはレンダーの完了時に毎回実行されるので、更新頻度が多いとやりすぎな場合がある
なので、副作用関数内で使用している特定のプロパティが変化した場合のみ実行するために、第 2 引数として、この副作用が依存している値の配列を渡しておくことができる
useEffect( () => { const subscription = props.source.subscribe(); return () => { subscription.unsubscribe(); }; }, [props.source], );
空配列[]
の場合はこの副作用がコンポーネント内のどの値にも依存していないということを React に伝えることになるので、初回マウント時に実行され、更新時には実行されないようになる