👻

useLayoutEffect と useEffect の特徴と違い

2024/07/28に公開

概要

React の useEffectuseLayoutEffect は、関数コンポーネント内で副作用を処理するためのフックです。これらはどちらも副作用(データフェッチ、DOM 操作、サブスクリプションなど)を処理するために使用されますが、実行タイミングと目的に違いがあります。

useLayoutEffect

特徴

  1. 実行タイミング:

    • useLayoutEffect は、DOM の変更がコミットされた後、ブラウザが再描画を行う前に実行されます。このため、UIの描画に先立って副作用が処理されます。
  2. 同期的な処理:

    • useLayoutEffect同期的に実行されます。これは、関数がブロックされ、すべての副作用が完了するまで次の描画が行われないことを意味します。
  3. 用途:

    • レイアウトの測定や同期的なDOM操作に適しています。たとえば、要素のサイズを計測してその情報をもとに他のDOM操作を行う場合に使用されます。

使用例

import React, { useRef, useLayoutEffect, useState } from 'react';

const MeasureComponent = () => {
    // useRefを使ってdiv要素への参照を作成
    const divRef = useRef(null);
    // 要素の幅を状態として保持
    const [width, setWidth] = useState(0);

    // useLayoutEffectを使って要素の幅を測定
    useLayoutEffect(() => {
        if (divRef.current) {
            // getBoundingClientRect()を使って要素の幅を取得
            setWidth(divRef.current.getBoundingClientRect().width);
        }
    }, []); // 空の依存配列でマウント時にのみ実行される

    return (
        <div>
            <div ref={divRef} style={{ width: '200px', height: '100px', background: 'lightblue' }}>
                This div's width is measured.
            </div>
            <p>The above div's width is: {width}px</p>
        </div>
    );
}

export default MeasureComponent;

useLayoutEffect の実行タイミング
  • useLayoutEffect フックは、React がDOMの変更をコミットした後、ブラウザが描画を行う前に実行されます。
  • つまり、DOMの変更が確定した直後に実行されるため、DOMの要素が存在し、その寸法を正確に測定することができます。
初期レンダリング時のフロー
  1. 初期レンダリング開始:

    • コンポーネントが初めてレンダリングされるとき、divRef はまだ null です。
    • render 関数が実行され、JSX が仮想DOMとして作成されます。
  2. DOMのコミット:

    • 仮想DOMがリアルDOMに反映され、div 要素がDOMツリーに追加されます。
    • ref={divRef} の部分が処理され、divRef.currentdiv 要素が設定されます。
  3. useLayoutEffect の実行:

    • DOM の変更がコミットされた直後、useLayoutEffect が実行されます。
    • この時点で、divRef.currentdiv 要素を指しているため、if (divRef.current) の条件は true になります。
    • getBoundingClientRect().width を使って div 要素の幅を取得し、setWidth により width 状態を更新します。

useEffect

特徴

  1. 実行タイミング:

    • useEffect は、DOM の変更が描画された後に実行されます。これにより、非同期の副作用(データフェッチ、タイマーの設定、サブスクリプションの設定など)を処理するのに適しています。
  2. 非同期的な処理:

    • useEffect は非同期的に実行されます。描画がブロックされることなく、スムーズなユーザーインターフェースが維持されます。
  3. 用途:

    • 非同期の副作用に適しており、例えばAPIからのデータフェッチやイベントリスナーの設定などに使用されます。

useLayoutEffectuseEffect の違い

  1. 実行タイミングの違い:

    • useEffect: DOM の変更が描画された後に実行されます。これは、非同期の副作用に適しています。
    • useLayoutEffect: DOM の変更がコミットされた直後、描画が行われる前に実行されます。これは、同期的なDOM操作に適しています。
  2. パフォーマンスの影響:

    • useEffect は非同期に実行されるため、描画パフォーマンスに影響を与えません。これにより、ユーザーインターフェースがスムーズに保たれます。
    • useLayoutEffect同期的に実行されるため、複雑な計算や長時間かかる処理を行うと描画がブロックされる可能性があります。そのため、主に短時間で完了するレイアウト操作に使用されます。
  3. 使用するシナリオ:

    • useEffect: 非同期の副作用(データフェッチなど)に適しています。
    • useLayoutEffect: 同期的な副作用(同期的なDOM操作など)に適しています。

まとめ

Reactの useEffectuseLayoutEffect は、どちらも副作用を処理するためのフックですが、実行タイミングと用途に違いがあります。useEffect は非同期の副作用に適しており、描画後に実行されます。一方、useLayoutEffect は同期的な副作用に適しており、描画前に実行されます。これらを適切に使い分けることで、効率的でパフォーマンスの高いReactコンポーネントを作成することができます。

Discussion