どうも、ノマドクリエイターのショウヘイ(@shohei_creator)です。
ブログアシスタントのふーちゃんです。
React には、 DOM が生成されてから破壊されるまでのライフサイクルうち、特定の時点に関数を実行できるフックがいくつか用意されています。 DOM のマウント後に関数を起動できる useEffect は、頻繁に使われている便利なフックです。
一方で、 DOM のマウント前に関数を起動できる useLayoutEffect というフックも用意されています。ブラウザの読み込み直後のコンポーネントのチラつき防止など、用途は限定されがちですが、何かと便利です。
この記事では、 React の useLayoutEffect フックの使い方について説明します。
React の useLayoutEffect フックとは
React の useLayoutEffect フックは、 React のライフサイクルのうち、 DOM がマウント・更新される時の直前に、関数を実行できるものです。
React で頻繁に使われている useEffect フックは、 DOM がマウント・更新される時の直後に関数を実行できるものです。
DOM がマウント・更新される前後のどちらに関数を実行させたいのかによって、 useLayoutEffect フックと useEffect フックは使い分けられます。
React のライフサイクル図のうち、「 Commit ステージ」の「 React が DOM と refs を更新する」の直前に、 useLayoutEffect フックが起動します。
React lifecycle methods diagram
React の useLayoutEffect フックの基本構文と使い方
React の useLayoutEffect フックは、コンポーネントの中で使います。また、使う時には、 2 つの引数を設定します。
useLayoutEffect フックの第 1 引数には、実行したい関数を設定します。関数の書き方は、アロー関数でも構いません。 useLayoutEffect フックの第 2 引数には、 useLayoutEffect フックの起動を制御するために監視したい変数を要素として持つ配列を設定します。
こちらは、 JavaScript で useLayoutEffect を書いた場合のコードです。 ちなみに、 TypeScript で書いた場合でも、基本構文は大差ないです。
import React, { useLayoutEffect } from "react";
export const Component = () => {
useLayoutEffect (
// 実行したい関数
() => {
(省略)
},
// 変更を監視したい変数を要素に持つ配列
[var1, var2, var3]
);
(以下、省略)
};
実際に useLayoutEffect フックを使う時は、 react ライブラリから import することを忘れないでください。
import React, { useLayoutEffect } from "react";
React の useEffect フックと useLayoutEffect フックの違い
React の useEffect フックと useLayoutEffct フックの違いは、関数を実行できる時点です。
useEffect フックは、 DOM がマウント・更新される時の直後に起動します。
React の useLayoutEffect フックは、 DOM がマウント・更新される時の直前に起動します。
useEffect フックと useLayoutEffect フックが起動する時点の違いは、 console.log を使ってみると分かりやすいですね。
useState フックを使ってレンダリングを実行させるボタンも作ったので、何度かボタンをクリックして、 console.log の出力順を確認してみてください。
useLayoutEffect フックの方が、先に起動していますね。
import React, { useEffect, useLayoutEffect, useState } from "react";
export const Component: React.VFC = () => {
const [state, setState] = useState<boolean>(true);
useLayoutEffect(() => {
console.log("useLayoutEffectフックが起動");
}, [state]);
useEffect(() => {
console.log("useEffectフックが起動");
}, [state]);
return (
<>
<button onClick={() => setState((preState) => !preState)}>
レンダリングさせる
</button>
</>
);
};