レイアウトスラッシングと視覚的なちらつきの回避
useEffectが目に見えるちらつきを引き起こす状況を特定し、useLayoutEffectに置き換えて修正します
「レイアウトスラッシングと視覚的なちらつきの回避」はCoddyKit上の無料React Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Academyコースには全4レッスンが含まれています。
レイアウトスラッシングとは
レイアウトスラッシングは、JavaScriptがループ内でDOMプロパティの読み取りとDOMへの書き込みを交互に行うと発生します。書き込みの後に読み取りを行うたびに、正確な値を返すため、ブラウザはレイアウトを同期的に再計算しなければなりません。その結果、本来は1回で済むレイアウト計算が数十回に及び、性能が大幅に低下する可能性があります。
Reactのバッチ更新による改善
Reactは、イベントハンドラーやエフェクト内で行われるすべてのsetState呼び出しを、1回の再レンダーにまとめます。この自然なバッチ処理により、1回のレンダーサイクル内でレイアウトスラッシングの原因となる読み取り・書き込み・読み取りのパターンを防げます。React 18では、バッチ処理が非同期コールバックやPromiseにも拡張され、state更新が同時に行われる場合のレイアウトスラッシングも軽減されます。
useEffectでちらつきが発生する場合
ちらつきは、useEffectがDOMを読み取り、状態を更新して再レンダリングを発生させた結果、ブラウザが初期状態と修正後の状態の2回描画するときに発生します。最初の描画は一瞬だけ表示された後、置き換えられます。これは、高さ、幅、位置などのレイアウトプロパティを調整するエフェクトで特に顕著です。
DevToolsでちらつきを診断する
Chrome DevToolsを開き、三点メニューの「More tools」から「Rendering」タブを開いて、「Paint flashing」を有効にします。再描画された領域が緑色で強調表示されます。初回レンダリング時にコンポーネントがちらつき、その直後に異なるレイアウトへ再描画される場合は、useEffectによる状態更新が原因の二重描画であることを確認できます。
useLayoutEffectへ移行してちらつきを修正する
DOMの読み取りと、それによって発生する状態更新をuseEffectからuseLayoutEffectへ移します。同じ測定と状態更新が描画前に同期的に行われるため、Reactは同じ処理の中で再レンダリングとコミットを実行し、ブラウザは最終的な正しい状態だけを描画します。DevToolsでの緑色の点滅も消えます。
1回の描画で完了させるパターン
ちらつきを防ぐパターンは、useLayoutEffectでDOMを読み取り、測定結果をsetStateに渡し、Reactが同期的に再レンダリングし、修正後のDOMをコミットして、ブラウザが最終結果を1回だけ描画するという流れです。これは、ツールチップの位置調整、固定ヘッダーのオフセット、アニメーションのセットアップにおける標準的なパターンです。
useEffectが適しているケース
エフェクトの大部分はuseEffectに置きます。データ取得(読み込み中のちらつきは許容され、想定されるものです)、イベントやストリームの購読、ログ出力と分析、タイマー、そして表示中のレイアウトに直ちに影響しないエフェクトが該当します。useEffectで対応できる箇所にuseLayoutEffectを過剰に使用するのはアンチパターンであり、パフォーマンスを損ないます。
useLayoutEffectが適しているケース
useLayoutEffectは、視覚的な出力に反映するDOMの測定に限定して使用します。たとえば、ツールチップの位置、要素のサイズに基づくロジック、スクロール位置の復元、初期サイズを読み取るアニメーションのセットアップなどです。切り替えを検討すべき明確な兆候は、初回レンダリング時にレイアウトが一瞬だけ誤って表示されることです。
コードでuseEffectとuseLayoutEffectを比較する
2つのフックのシグネチャは同じです。useLayoutEffect(callback, deps)とuseEffect(callback, deps)の違いは、コールバックが実行されるタイミングだけです。コード中の1語を変更するだけで、両者を切り替えられます。まずはuseEffectを使い、ちらつきを確認した場合にだけuseLayoutEffectへ変更してください。
1つのコンポーネントで両方を組み合わせる
同じコンポーネント内で、異なる関心事に対して両方のフックを使うことは有効で、一般的でもあります。たとえばチャートコンポーネントでは、useLayoutEffectでコンテナの幅を測定してSVGのviewBoxを同期的に設定し、その後useEffectでチャートデータを非同期に取得できます。それぞれのフックが、タイミングが重要となる関心事を担当します。
二重描画をテストする
DevToolsのPaint flashingに加えて、コンポーネント内にコンソールカウンターを追加し、レンダリング回数を数えることもできます。初回マウント時にコンポーネントが「render」と2回ログを出力し、1回目が初期状態、2回目が修正後の測定結果である場合は、二重描画が発生しています。測定処理をuseLayoutEffectへ移すと、マウント後に記録されるレンダリングは1回に減るはずです(Strict Modeでは2回になる点を除きます)。
useEffectよりuseLayoutEffectを優先するタイミング
useEffectではなくuseLayoutEffectを使う正しい理由は、次のうちどのケースでしょうか。
レッスンのまとめ:レイアウトスラッシングと視覚的なちらつき
レイアウトスラッシングは、DOMの読み取りと書き込みを交互に行うことで発生します。Reactのバッチ処理により、レンダリング中に発生するレイアウトスラッシングの大部分は防止されます。useEffectでDOMを測定して状態を更新すると、2回の描画が発生してちらつきます。DOMの測定をuseLayoutEffectへ移して、ちらつきを修正してください。それ以外は、データ取得、購読、ログ出力、タイマーを含め、基本的にuseEffectを使用します。
よくある質問
「レイアウトスラッシングと視覚的なちらつきの回避」レッスンは無料ですか?
はい。「レイアウトスラッシングと視覚的なちらつきの回避」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Academyコースには全4レッスンが含まれています。
「レイアウトスラッシングと視覚的なちらつきの回避」で何を学びますか?
useEffectが目に見えるちらつきを引き起こす状況を特定し、useLayoutEffectに置き換えて修正します ブラウザで直接実行するハンズオンコードでReact Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
React Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのReact Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「レイアウトスラッシングと視覚的なちらつきの回避」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このReact Academyレッスンでコードを書いて実行できますか?
はい。すべてのReact Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- レンダリングフェーズとDOMコミット
- useLayoutEffectとuseEffectの実行タイミング
- useLayoutEffectによるDOM要素の測定
- レイアウトスラッシングと視覚的なちらつきの回避