useDeferredValue 完全入門【React】値の更新を遅延させてUIを快適に

ReactのuseDeferredValueとは何か、値の更新を遅延させてUIの応答性を維持する仕組みを初心者向けに解説。useTransitionとの使い分けや検索フィルタリングでの実装例も紹介します。

#react#hooks#usedeferredvalue#javascript#frontend

「検索ボックスの入力が重い……でも入力 state には直接触れない」——そんな状況で役立つのが useDeferredValue です。

useTransition と似ていますが、こちらは値そのものを遅延させます。props や外部から渡ってくる値に対して、遅延バージョンを作ることができます。

この記事でわかること:

  • useDeferredValue の仕組みと使いどころ
  • 検索フィルタリングでの実装パターン
  • useTransition との違い・使い分け
  • デバウンス・スロットリングとの違い

useDeferredValue とは?

useDeferredValue は、値の更新を遅延させて、重い処理をバックグラウンドで行うフックです。

const deferredValue = useDeferredValue(value);
パラメータ説明
value遅延させたい任意の値

返り値は value の「遅延バージョン」です。最初のレンダリングでは元の値と同じですが、更新時は古い値を保ちながらバックグラウンドで新しい値への更新を試みます。

動作の仕組み

入力: "react"

① React は deferredQuery = "" のまま、最新の query = "react" で描画
② バックグラウンドで query = "react" の deferredQuery = "react" への更新を試みる
③ 完了したら deferredQuery = "react" で再描画

(この間、ユーザーは "hooks" と追加入力できる)

デバイスの性能に応じて自動で遅延量が調整されます。高速なデバイスではほぼ即時、低速なデバイスでは適切な遅延が入ります。

基本的な使い方

import { useState, useDeferredValue } from "react";
 
function SearchPage() {
  const [query, setQuery] = useState("");
 
  // query の遅延バージョン
  const deferredQuery = useDeferredValue(query);
 
  // deferredQuery が古い値のとき → 古い結果を薄く表示
  const isStale = query !== deferredQuery;
 
  return (
    <>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="検索..."
      />
 
      {/* deferredQuery を使うことで重い処理を遅延させる */}
      <div style={{ opacity: isStale ? 0.5 : 1 }}>
        <SearchResults query={deferredQuery} />
      </div>
    </>
  );
}

query !== deferredQuery のときは「古い結果を薄く表示」することで、更新中であることをユーザーに伝えられます。

memo と組み合わせて効果を最大化

useDeferredValue の効果を最大限に発揮するには、遅延させる値を受け取るコンポーネントを memo でラップします。

import { memo, useDeferredValue, useState } from "react";
 
// memo でラップ:deferredQuery が変わらない限り再レンダリングしない
const HeavyList = memo(function HeavyList({ query }) {
  const items = filterItems(allItems, query); // 重いフィルタリング
 
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
});
 
function SearchPage() {
  const [query, setQuery] = useState("");
  const deferredQuery = useDeferredValue(query);
 
  return (
    <>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      {/* deferredQuery が変わったときだけ HeavyList が再レンダリングされる */}
      <HeavyList query={deferredQuery} />
    </>
  );
}

memo がないと、deferredQuery が変わっていなくても親のレンダリングで子も再レンダリングされてしまいます。

useTransition との使い分け

フック遅延させるもの使う場面
useTransition状態更新のコード自分でイベントハンドラを書ける場合
useDeferredValue受け取った値props や外部から来る値を遅延させたい場合
// useTransition を使う場合(自分で更新をコントロールできる)
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
  setQuery(e.target.value);
  startTransition(() => {
    setResults(filterItems(e.target.value));
  });
};
 
// useDeferredValue を使う場合(props として受け取る場合)
function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);
  return <HeavyList query={deferredQuery} />;
}

デバウンス・スロットリングとの違い

手法仕組み特徴
デバウンス入力停止後に実行遅延時間が固定
スロットリング一定間隔で実行遅延時間が固定
useDeferredValueReact のスケジューリングに委ねるデバイス性能に自動適応

useDeferredValue はタイマーを使わずに React のレンダリングシステムに統合されているため、デバイスの性能に応じて柔軟に動作します。

まとめ

  • useDeferredValue は値の更新を遅延させて、UIの応答性を維持するフック
  • query !== deferredQuery で更新中かどうかを判定できる
  • memo でラップした子コンポーネントと組み合わせると効果的
  • 自分でイベントを操作できる場合は useTransition が適している
  • デバイスの性能に自動で適応するため、固定のタイマーより柔軟

PR

useDeferredValue 公式ドキュメントで詳細を確認しよう

useDeferredValueのインタラクティブなサンプルや、useTransitionとの詳しい比較は公式ドキュメントで確認できます。

useDeferredValue 公式ドキュメントを見る

関連記事