useDeferredValue Hook
useDeferredValue Hook — արժեքների հետաձգում UI-ի օպտիմիզացիայի համար
useDeferredValue-ը React 18-ի hook է, որը թույլ է տալիս React-ին հետաձգել արժեքների թարմացումը, որպեսզի UI-ը մնա արագ և արձագանքող։ Այն շատ նման է debounce-ի գաղափարին, բայց React-ի մակարդակում՝ առանց հավելյալ timeout-ների։
Երբ ունես input և մեծ ցուցակ, որը կախված է այդ input-ից, React-ը կարող է պահել input-ի անմիջական արձագանքը և մի փոքր ուշացնել ցուցակի թարմացումը՝ կանխելով UI-ի դանդաղեցում։
const deferredValue = useDeferredValue(value);
Եթե `value` փոխվի, React-ը կթարմացնի այն անմիջապես UI-ի համար, բայց `deferredValue` կթարմացվի միայն այն ժամանակ, երբ React-ը ազատ լինի heavy rendering-ից։
import React, { useState, useDeferredValue, useMemo } from 'react';
export default function SearchDeferred() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const items = useMemo(() => {
const data = Array.from({ length: 5000 }, (_, i) => `Item ${i + 1}`);
return data.filter((item) => item.toLowerCase().includes(deferredQuery.toLowerCase()));
}, [deferredQuery]);
return (
<div>
<h2>🔍 useDeferredValue filtering</h2>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Գրի՛ր ինչ-որ բան..."
/>
<p>
{query !== deferredQuery ? '⏳ Թարմացվում է...' : '✅ Պատրաստ է'}
</p>
<ul>
{items.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
);
}
Այս օրինակում օգտվողը կարող է գրել input-ում առանց ուշացման, քանի որ React-ը հետաձգում է ծանր filtering գործընթացը՝ մինչ նա ավարտի մուտքագրումը։ `deferredQuery`-ն թարմացվում է մի փոքր ուշ, բայց UI-ն միշտ արագ է։
| useTransition | useDeferredValue |
|---|---|
| Կառավարում է update-ը (գործողությունը) | Կառավարում է արժեքը (տվյալը) |
| Օգտագործվում է՝ նշելու համար որ update-ը non-urgent է | Օգտագործվում է՝ հետաձգելու արդեն գոյություն ունեցող state արժեքը |
| Անհրաժեշտ է startTransition(callback) | Պարզապես փոխանցում ես value՝ ստանում deferred տարբերակը |
| Հարմար է state փոփոխությունների կառավարման համար | Հարմար է derived data-ի հաշվարկման համար |
// useTransition տարբերակ
const [isPending, startTransition] = useTransition();
startTransition(() => {
setFiltered(items.filter(...));
});
// useDeferredValue տարբերակ
const deferredQuery = useDeferredValue(query);
const filtered = useMemo(() =>
items.filter(item => item.includes(deferredQuery)), [deferredQuery]);
Երկուսն էլ լուծում են UI-ի lag-ի խնդիրը, բայց useDeferredValue-ն ավելի պարզ է, երբ աշխատում ես մեկ կոնկրետ արժեքի հետ։
import React, { useState, useDeferredValue } from 'react';
import { LineChart, Line, XAxis, YAxis } from 'recharts';
export default function DeferredChart() {
const [range, setRange] = useState(100);
const deferredRange = useDeferredValue(range);
const data = Array.from({ length: deferredRange }, (_, i) => ({
x: i,
y: Math.sin(i / 10) * 50 + 50,
}));
return (
<div>
<h3>📊 Deferred Chart Example</h3>
<input
type="range"
min="100"
max="5000"
value={range}
onChange={(e) => setRange(Number(e.target.value))}
/>
<p>Էլեմենտներ՝ {deferredRange}</p>
<LineChart width={500} height={200} data={data}>
<XAxis dataKey="x" />
<YAxis />
<Line type="monotone" dataKey="y" stroke="#2196f3" />
</LineChart>
</div>
);
}
Այստեղ React-ը չի փորձում անմիջապես rerender անել ամեն slider շարժման ժամանակ։ Հակառակը, այն սպասում է՝ մինչև deferred value թարմանա, պահպանելով chart-ի սահուն աշխատանքը։
Գրիր կոմպոնենտ, որը․
Փորձիր համեմատել նույն կոդը առանց useDeferredValue-ի։ Կտեսնես՝ input-ը դանդաղ է արձագանքում մեծ տվյալների դեպքում։