Skip to main content

Що робить useDeferredValue()

Що робить useDeferredValue()

useDeferredValue(value) повертає «відкладену версію» значення. Якщо value часто змінюється (наприклад, при введенні в інпут), React може не одразу прокинути нове значення у важкі ділянки UI (списки, графіки), щоб інтерфейс лишався відгукливим. Ввід реагує миттєво, а «дорогий» рендер підтягується трохи пізніше.

Міні-приклад:

javascript
const [query, setQuery] = useState(''); const deferredQuery = useDeferredValue(query); // "повільна" копія // Важкий список фільтрується за deferredQuery, а не за миттєвим query const filtered = useMemo(() => heavyFilter(items, deferredQuery), [items, deferredQuery]);

Поки користувач друкує, query змінюється одразу (інпут не лагає), а deferredQuery оновиться трохи пізніше - важкий рендер не «сіпається» на кожен символ.


Чим useDeferredValue() схожий на debounce

Обидва прийоми згладжують часті зміни, щоб не викликати важку роботу занадто часто.

Схожість:

  • Знижують частоту «дорогих» переобчислень/рендерів при швидкому вводі.
  • Користувач бачить плавний UI без лагів.

Чим useDeferredValue() відрізняється від debounce

Головні відмінності - у рівні і семантиці:

КритерійuseDeferredValue()Debounce (наприклад, debounce(fn, 300))
Де працюєВсередині React, розуміє пріоритети, інтегрований з Concurrent RenderingПоза React (утиліта часу), «тупо» затримує виклики
Що відкладаєПрокидання значення в споживачів; рендер можна перервати/поновитиВиклик функції за таймером після паузи
Керування затримкоюДинамічне, без жорсткого таймера; React сам вирішує, коли «наздогнати»Жорсткий інтервал (наприклад, 300 мс)
Скасування/перериванняТак: рендер можна перервати, якщо прийшло важливіше оновленняТак: скидання таймера при новому вводі, але без знань про пріоритети React
SSR/гідратація/конкурентністьПриродно суміснийНіяк не інтегрований
Типові кейсиРозділити «швидкий» ввід і «важкий» UIМережа/обробники, обмеження частоти викликів, autocomplete API

Підсумок: debounce - про час, useDeferredValue - про пріоритети рендеру.


Чим useDeferredValue() відрізняється від startTransition()

Обидва механізми служать для «нетермінових» оновлень, але точка застосування різна:

КритерійuseDeferredValue(value)startTransition(() => setState(...))
РівеньЗначення: віддає «повільну» копію часто змінюваного valueОперація/оновлення: позначає конкретні setState як низькопріоритетні
Хто ініціюєСпоживач значення обирає «повільну» версіюТи сам позначаєш частину оновлень як transition
Контроль статусуНемає вбудованого isPendingЧерез useTransition() отримуєш isPending
ГранулярністьПасивна: будь-яке місце, де використовуєш deferred value, буде «наздоганяти» пізнішеАктивна: ти явно обгортаєш «важкі» оновлення в transition
Типові кейсиВажкі мемо-обчислення/списки, що залежать від швидко змінюваного valueНавігація, фільтрація, запити, масштабні перебудови дерева
Асинхронність (React 19+)Не про asyncstartTransition можна await-нути (очікувати async роботу)

Коротко:

  • useDeferredValue - «дай мені версію цього значення, яку можна оновити пізніше».
  • startTransition - «оці оновлення стану зроби низькопріоритетними».

Коли що обирати

  • Важкий список/графік реагує на швидкий ввід → почни з useDeferredValue(query). Просто і майже без коду.
  • Потрібно позначити пакет оновлень як «нетерміновий» і показати статус «триває оновлення» → const [isPending, startTransition] = useTransition(); startTransition(() => setState(...)).
  • Обмежити частоту мережевих викликів / обробників вводу → debounce (мережевий шар/утиліти). Можна комбінувати: debounce на запит, useDeferredValue - для важкого UI.

Часті патерни

Комбо «інпут + deferred фільтрація»:

javascript
const [query, setQuery] = useState(''); const deferred = useDeferredValue(query); const list = useMemo(() => heavyFilter(items, deferred), [items, deferred]);

Позначити перебудову як перехідну (з індикатором):

javascript
const [isPending, startTransition] = useTransition(); const onTabChange = (tab: string) => { startTransition(() => setActiveTab(tab)); // велика перебудова дочірніх }; return <> <Tabs onChange={onTabChange} /> {isPending && <Skeleton />} <HeavyPane tab={activeTab} /> </>;

Debounce тільки для запиту:

javascript
const debouncedFetch = useMemo(() => debounce(fetchUsers, 300), []); useEffect(() => { debouncedFetch(query); }, [query, debouncedFetch]);

(і паралельно можна використати useDeferredValue(query) для «плавного» UI)


Вижимка

  • useDeferredValue - відкладена версія значення. Про пріоритети, не про таймер.
  • Debounce - таймер: відкладає виклики функцій після паузи.
  • startTransition - позначення оновлень стану як низькопріоритетних, з isPending і (в React 19+) await.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.