👻
useLayoutEffect と useEffect の特徴と違い
概要
React の useEffect
と useLayoutEffect
は、関数コンポーネント内で副作用を処理するためのフックです。これらはどちらも副作用(データフェッチ、DOM 操作、サブスクリプションなど)を処理するために使用されますが、実行タイミングと目的に違いがあります。
useLayoutEffect
特徴
-
実行タイミング:
-
useLayoutEffect
は、DOM の変更がコミットされた後、ブラウザが再描画を行う前に実行されます。このため、UIの描画に先立って副作用が処理されます。
-
-
同期的な処理:
-
useLayoutEffect
は同期的に実行されます。これは、関数がブロックされ、すべての副作用が完了するまで次の描画が行われないことを意味します。
-
-
用途:
- レイアウトの測定や同期的な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の要素が存在し、その寸法を正確に測定することができます。
初期レンダリング時のフロー
-
初期レンダリング開始:
- コンポーネントが初めてレンダリングされるとき、
divRef
はまだnull
です。 -
render
関数が実行され、JSX が仮想DOMとして作成されます。
- コンポーネントが初めてレンダリングされるとき、
-
DOMのコミット:
- 仮想DOMがリアルDOMに反映され、
div
要素がDOMツリーに追加されます。 -
ref={divRef}
の部分が処理され、divRef.current
にdiv
要素が設定されます。
- 仮想DOMがリアルDOMに反映され、
-
useLayoutEffect
の実行:- DOM の変更がコミットされた直後、
useLayoutEffect
が実行されます。 - この時点で、
divRef.current
はdiv
要素を指しているため、if (divRef.current)
の条件はtrue
になります。 -
getBoundingClientRect().width
を使ってdiv
要素の幅を取得し、setWidth
によりwidth
状態を更新します。
- DOM の変更がコミットされた直後、
useEffect
特徴
-
実行タイミング:
-
useEffect
は、DOM の変更が描画された後に実行されます。これにより、非同期の副作用(データフェッチ、タイマーの設定、サブスクリプションの設定など)を処理するのに適しています。
-
-
非同期的な処理:
-
useEffect
は非同期的に実行されます。描画がブロックされることなく、スムーズなユーザーインターフェースが維持されます。
-
-
用途:
- 非同期の副作用に適しており、例えばAPIからのデータフェッチやイベントリスナーの設定などに使用されます。
useLayoutEffect
と useEffect
の違い
-
実行タイミングの違い:
-
useEffect
: DOM の変更が描画された後に実行されます。これは、非同期の副作用に適しています。 -
useLayoutEffect
: DOM の変更がコミットされた直後、描画が行われる前に実行されます。これは、同期的なDOM操作に適しています。
-
-
パフォーマンスの影響:
-
useEffect
は非同期に実行されるため、描画パフォーマンスに影響を与えません。これにより、ユーザーインターフェースがスムーズに保たれます。 -
useLayoutEffect
は同期的に実行されるため、複雑な計算や長時間かかる処理を行うと描画がブロックされる可能性があります。そのため、主に短時間で完了するレイアウト操作に使用されます。
-
-
使用するシナリオ:
-
useEffect
: 非同期の副作用(データフェッチなど)に適しています。 -
useLayoutEffect
: 同期的な副作用(同期的なDOM操作など)に適しています。
-
まとめ
Reactの useEffect
と useLayoutEffect
は、どちらも副作用を処理するためのフックですが、実行タイミングと用途に違いがあります。useEffect
は非同期の副作用に適しており、描画後に実行されます。一方、useLayoutEffect
は同期的な副作用に適しており、描画前に実行されます。これらを適切に使い分けることで、効率的でパフォーマンスの高いReactコンポーネントを作成することができます。
Discussion