useDeferredValue 完全入門【React】値の更新を遅延させてUIを快適に
ReactのuseDeferredValueとは何か、値の更新を遅延させてUIの応答性を維持する仕組みを初心者向けに解説。useTransitionとの使い分けや検索フィルタリングでの実装例も紹介します。
「検索ボックスの入力が重い……でも入力 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} />;
}デバウンス・スロットリングとの違い
| 手法 | 仕組み | 特徴 |
|---|---|---|
| デバウンス | 入力停止後に実行 | 遅延時間が固定 |
| スロットリング | 一定間隔で実行 | 遅延時間が固定 |
useDeferredValue | React のスケジューリングに委ねる | デバイス性能に自動適応 |
useDeferredValue はタイマーを使わずに React のレンダリングシステムに統合されているため、デバイスの性能に応じて柔軟に動作します。
まとめ
useDeferredValueは値の更新を遅延させて、UIの応答性を維持するフックquery !== deferredQueryで更新中かどうかを判定できるmemoでラップした子コンポーネントと組み合わせると効果的- 自分でイベントを操作できる場合は
useTransitionが適している - デバイスの性能に自動で適応するため、固定のタイマーより柔軟
PR
useDeferredValue 公式ドキュメントで詳細を確認しよう
useDeferredValueのインタラクティブなサンプルや、useTransitionとの詳しい比較は公式ドキュメントで確認できます。
useDeferredValue 公式ドキュメントを見る →