useDeferredValue
from React Hooks
UIの一部の更新を遅延させる
重い計算や再レンダリングを遅延させて、ユーザ入力などの即時反応を滑らかに保つ
stateをwrapして使う
docs
基本的な役割
code:tsx
const deferredValue = useDeferredValue(value);
value を即座に反映しない遅延版の値(deferredValue)を返す
React は value の変化に対して、UI 更新を後回しにできる部分を自動的にスケジュールする
イメージ的には、debounceのようなものかmrsekut.icon
ただし、通常のdebounceは指定した秒数を基準にして更新頻度を制御するのに対し、
useDeferredValueは最適なrender回数になるように内部で制御されている
useDeferredValueとuseTransitionを特殊なdebounceとして捉える
更に異なる点として、
途中でrenderingを放棄できる
transitionを使ってsuspend時にfallbackを表示させない
データが読み込まれるまでは、以前の値が表示され続ける
例
code:tsx
import { useState, useDeferredValue } from "react";
function SearchList({ items }: { items: string[] }) {
const query, setQuery = useState("");
const deferredQuery = useDeferredValue(query);
const filtered = items.filter((item) =>
item.toLowerCase().includes(deferredQuery.toLowerCase())
);
return (
<>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
<ul>
{filtered.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</>
);
}
初回render時は、引数と結果の値は一致する
引数の値の更新時、入力 (query) は即座に反映される
しかし、filtered の再計算は一呼吸遅れて行われる
その間、UIはブロックされずスムーズに入力できる
内部の仕組み
内部では、Transitionとして扱われる
これは startTransition とほぼ同じ仕組みである
イメージ、以下はほぼ同じ
code:tsx
const deferredValue = useDeferredValue(value);
code:ts
let deferredValue;
startTransition(() => {
deferredValue = value;
});