fluid_27’s blog

勉強した内容をアウトプットするためのブログ

useEffectとuseLayoutEffectの違いって結局なんや?

React勉強した人は通るであろう、useEffectとuseLayoutEffectの違いについて。
ググってみると色んなサイトで説明がありますが、自分なりに整理しました。

useEffectとuseLayoutEffectの違いについて

結論

→実行タイミングの違い。

useEffect

・非同期で実行
コンポーネントレンダリング後に非同期で実行されるため、コンポーネントの表示に影響を与えない操作に適している。
・使う局面としてはネットワークリクエスト、データの取得、DOMの変更、ログの出力などの遅延可能な操作を行うために適している。

useLayoutEffect

・同期的に実行
コンポーネントレンダリング後(仮想DOMの構築後)、DOMが更新される前に実行されるため、DOMの計算や計測、ブラウザでの描画前にスクロール位置を設定するなど、表示に関連する操作が必要な場合に使用する。
・ブラウザの描画前に実行されるため、useEffectだと発生する画面のちらつき(初期表示されてから瞬時にuseEffectによりブラウザが再描画する挙動)が避けられる。

※useEffectの画面のちらつきについては以下ブログでの説明が分かりやすいです。
useEffectのちらつきを無くしたいときの対処法【useLayoutEffect】

ただ、どのサイトでも説明されている通り、一般的にuseEffectを使うことが多く、useLayoutEffectを使う局面は限られている。

一般的にuseEffectが使われる理由

結論

→非同期による処理でユーザーエクスペリエンスを向上させつつ、アプリケーションのパフォーマンスを維持するため。

以下詳細。

非同期処理によるユーザーエクスペリエンスの向上

useEffectは非同期で実行されるので、コンポーネントレンダリングと関連する操作を遅延させない。
例えば、ネットワークリクエストやデータの取得など、時間がかかる操作を同期的に行うと、ユーザーがコンポーネントの表示を待たされることになり、ユーザーエクスペリエンスが悪化するが、useEffectは非同期に実行されるため、ユーザーエクスペリエンスを悪化を防ぐことができる。

パフォーマンス

useLayoutEffectは描画前に同期的な処理を行うため、コンポーネントレンダリングと関連する操作を遅延する可能性がある。
特に、複数のuseLayoutEffectが連続して呼ばれる場合、ブラウザの描画をブロックしてしまう可能性があるので、一般的なユースケースでは非同期操作(useEffect)が適切な場面であることが多い

useLayoutEffectの方が向いている局面

useEffectはブラウザでの描画が完了した後に非同期操作が実行されるため、コンポーネントの表示に直接影響を与えない操作(例: ログの出力)に適している。
ただし、ブラウザは非同期操作をキューに追加して実行しており、非同期処理の順序は保証されない。ので、操作の順序が重要な場合はuseLayoutEffectが使用される。

Reactでブラウザがレンダリングされるまでの流れ

1. 仮想DOMの構築(Render)

Reactコンポーネントレンダリングが行われ、仮想DOMが構築される。この段階では、まだ実際のDOMへの変更は行われない。

2. 実際のDOMへの変更(Reconciliation)

仮想DOMと前回のレンダリングの仮想DOMとの差分が計算され、必要なDOMの変更が特定される。この段階で実際のDOMへの変更が行われる。

3. ブラウザの描画(Painting)

DOMの変更が適用され、ブラウザが再描画を行なわれる。

まとめ

改めてuseEffectとuseLayoutEffectの実行タイミングの違いを確認

useEffect

→ブラウザの描画の後に非同期で実行される。

useLayoutEffect

→仮想DOMの構築が完了して、実際のDOMの変更の前に同期的に実行される。

大体のケースではuseEffectを使用するのが最適解。