HOME  >  Web開発 >  【React.js】useLayoutEffectとuseDeferredValueの使い方をご紹介(React hooksを学ぶ)

Web開発

【React.js】useLayoutEffectとuseDeferredValueの使い方をご紹介(React hooksを学ぶ)

【React.js】useLayoutEffectとuseDeferredValueの使い方をご紹介(React hooksを学ぶ)

目次

  1. useLayoutEffectについて
  2. useDeferredValueについて
  3. 最後に

今回は、React hooksの中のuseLayoutEffectとuseDeferredValueの二つのフックを紹介します。

useLayoutEffectは以前紹介した、useEffectと同様の副作用処理のフックであり、useDeferredValueは緊急性の低い値を対象として、値の更新を遅延させるフックになります。

これまで学んできたReact hooksについては下記記事をご覧ください。

【React.js】useStateとuseEffectの使い方をご紹介(React hooksを学ぶ)
https://www.dailyupblog.com/web_development/1888/

【React.js】useContextとuseReducerの使い方をご紹介(React hooksを学ぶ)
https://www.dailyupblog.com/web_development/1926/

【React.js】useCallbackとuseMemoの使い方をご紹介(React hooksを学ぶ)
https://www.dailyupblog.com/web_development/1956/

【React.js】useRefとuseImperativeHandleの使い方をご紹介(React hooksを学ぶ)
https://www.dailyupblog.com/web_development/1978/

それでは早速いきましょう。

useLayoutEffectについて

useLayoutEffectは、以前紹介したuseEffect同様に副作用処理のフックです。

useEffectに関しては下記記事をご覧ください。
https://www.dailyupblog.com/web_development/1888/#chapter-3

機能としては、useEffectと同じものになりますが、唯一の違いは実行タイミングです。

useEffectはコンポーネントのマウント時に非同期的に呼び出されます。

非同期的に呼び出されるため、画面描画後にuseEffectが実行されます。

それに対して、useLayoutEffectは、同期的に呼び出されます。

同期的に呼び出されるため、画面描画前にuseLayoutEffectが実行されます。

そのため、useLayoutEffectの場合は、少し時間がかかる処理などの場合には、一旦他の処理をストップしてでも、画面描画よりも前に処理されることになります。

早速例を見てみましょう。

今回はuseEffectとの違いを比べるために、useEffectとuseLayoutEffectの両方のパターンを紹介します。

「components」ディレクトリ内にUseLayoutEffect.tsxファイルを作成してください。

その中には下記のように記述します。

import { useEffect, useState } from "react";

const UseLayoutEffect = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    if (count === 0) setCount(Math.floor(Math.random() * (10000 - 1)) + 1);
  }, [count]);
  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(0)}>乱数出力</button>
    </div>
  );
};

export default UseLayoutEffect;

この例は、ボタンをクリックすることで、stateが一旦0にリセットされ、useEffectにて、stateを1〜10000のランダムな数値を出力するものです。

まず、useEffectですが、これを実行すると、ボタン押下の際に、出力されているstateの値が変化しますが、その際に一瞬のちらつきが出て変更されます。

これは、stateが0から乱数に変わるのが画面描画後のタイミングであるためです。

画面描画後に非同期的に値が更新されるため、このようなちらつきが起きてしまいます。

これに対して、下記はuseLayoutEffectの例です。

import { useEffect, useState } from "react";

const UseLayoutEffect = () => {
  const [count, setCount] = useState(0);

  useLayoutEffect(() => {
    if (count === 0) setCount(Math.floor(Math.random() * (10000 - 1)) + 1);
  }, [count]);
  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(0)}>乱数出力</button>
    </div>
  );
};

export default UseLayoutEffect;

書き方はuseEffectと全く一緒で、useEffectがuseLayoutEffectに変わっただけです。

これを実行すると、useEffectにあったような一瞬のちらつきは起きなくなりました。

これは、useLayoutEffectは画面描画前に同期的に実行されるため、値が乱数に変更されたのちにレンダリングされます。

なので、useEffectにあったような一瞬のちらつきは表示されなくなるのです。

さて、このようにuseEffectとuseLayoutEffectの違いを紹介しましたが、公式によれば、useEffectの方を使うことを推奨しているようです。

確かに、useLayoutEffectではちらつきが起きず、ユーザビリティ的にはいいかもしれませんが、同期処理のため、動作が一旦止まってしまう恐れがあり、結果的にパフォーマンスに影響を与える可能性があります。

useEffectとuseLayoutEffectの使い道としては、DOM操作の他にはサーバーへの通信やローカルストレージへの操作などが挙げられますが、基本的にはuseEffectを使い、useLayoutEffectは「描画」に関する処理に留めておくのがいいかもしれません。

useDeferredValueについて

useDeferredValueは、React18で追加されたフックで、緊急性の低い値を対象として、値の更新を遅延させるフックです。

ここでいう遅延させるとは、React側でいい感じに処理に暇ができたら、値を変化させるという意味合いになります。

なので、軽い処理であればそこまで遅延しませんが、処理が重ければ重いほど遅延します。

使い道としては、例えば画面の一部の値を遅延させたい時などで、画面内で優先度が低めの値の更新をあえて遅延させることで、パフォーマンスを向上させることができるというわけです。

早速、例を見てみましょう。

「components」ディレクトリ内にUseDeferredValue.tsxファイルを作成してください。

これに対して、下記はuseLayoutEffectの例です。

import { useDeferredValue, useState } from "react";

function UseDeferredValue() {
  const [searchTerm, setSearchTerm] = useState("");

  // 遅延バージョンの作成
  const deferredSearchTerm = useDeferredValue(searchTerm);

  console.log(searchTerm, deferredSearchTerm);

  return (
    <div>
      <input
        type="text"
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        placeholder="Search"
      />
      <p>{deferredSearchTerm}</p>
    </div>
  );
}

export default UseDeferredValue;

useDeferredValueは、値の遅延バージョンを作成します。

今回は、「searchTerm」というstateを用意しており、この「searchTerm」の遅延バージョンである「deferredSearchTerm」を作成しています。

その直後に「searchTerm」と遅延バージョンの「deferredSearchTerm」をconsole.logで出力しています。

これで、二つの値の違いを比べてみようと思います。

また、テキストフォームを設置し、onChangeで入力されるたびに、setSearchTermに入力された値をセットしています。

これにより、フォームに入力するたびに、「searchTerm」と「deferredSearchTerm」の値を更新します。

早速この例を実行してみてください。

するとフォームが表示されるので、試しに「abcdefghijk」と入力してみましょう。

下記のように、入力した内容が下に表示されます。

コンソールを見てみましょう。

すると下記のように、入力した内容のログが表示されていると思います。

strict modeで同じ値が何度か更新されていますが、それは置いておいて、「searchTerm」と「deferredSearchTerm」の値が並んでいます。

二つの値を見比べてみると、「abc」と「ab」のように遅延バージョンの値は更新が遅れているのが確認できると思います。

このようにuseDeferredValueを使うことで、優先度の低い値を、いい感じに遅延してくれます。

最後に

今回は、useLayoutEffectとuseDeferredValueをご紹介しました。

この二つとも使い方次第では便利なフックになりますので、適切な時に使っていきたいです。

次回はuseDeferredValueと同じくReact18で追加されたuseTransitionを紹介します。

前回:【React.js】useRefとuseImperativeHandleの使い方をご紹介(React hooksを学ぶ)
https://www.dailyupblog.com/web_development/1978/

次回:【React.js】useTransitionとuseIdの使い方をご紹介(React hooksを学ぶ)
https://www.dailyupblog.com/web_development/2020/

関連記事
  • 【React.js】CSS-in-JSを使ったスタイリング(……

  • 【React.js】CSS-in-JSを使ったスタイリング(

    【React.js】React.jsにおけるコンポーネントと……

  • 【React.js】React.jsにおけるコンポーネントと

    【React.js】Reduxを使ってstate(状態)を一……

  • 【React.js】Reduxを使ってstate(状態)を一

    【React.js】useRefとuseImperative……

  • 【React.js】useRefとuseImperative

    【React.js】React Routerで画面遷移をして……

  • 【React.js】React Routerで画面遷移をして

    【React.js】useTransitionとuseIdの……

  • 【React.js】useTransitionとuseIdの

    【React.js】React.jsとは?環境構築やHell……

  • 【React.js】React.jsとは?環境構築やHell

    【React.js】useStateとuseEffectの使……

  • 【React.js】useStateとuseEffectの使

    【React.js】useCallbackとuseMemoの……

  • 【React.js】useCallbackとuseMemoの

    【React.js】useContextとuseReduce……

関連記事

【React.js】Reduxを使ってstate(状態)を一元管理する。

【React.js】Reduxを使ってs……