Skip to main content

Що робить useDeferredValue() при роботі з асинхронністю?

Що робить useDeferredValue()

useDeferredValue(value) - відкладає оновлення значення, щоб React міг спочатку відрендерити швидкі й важливі частини інтерфейсу, а "важкі" чи асинхронні частини оновити трохи пізніше.

Іншими словами:

React робить UI відзивчивим, не блокуючи рендеринг повільних компонентів.


Просте пояснення

Уяви поле пошуку, де при кожному введенні символу йде запит на сервер:

javascript
<input value={query} onChange={e => setQuery(e.target.value)} /> <SearchResults query={query} />

Проблема:

  • користувач швидко друкує - query змінюється на кожен символ;
  • кожен рендер запускає фільтрацію або мережевий запит;
  • UI починає "лагати" (гальмувати при введенні).

1. Як вирішує useDeferredValue

javascript
import { useState, useDeferredValue, Suspense } from 'react'; import useSWR from 'swr'; const fetcher = (url) => fetch(url).then(r => r.json()); function SearchResults({ query }) { const { data } = useSWR(`/api/search?q=${query}`, fetcher, { suspense: true }); return <ul>{data.results.map(r => <li key={r}>{r}</li>)}</ul>; } export default function Search() { const [query, setQuery] = useState(''); const deferredQuery = useDeferredValue(query); return ( <> <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Пошук..." /> <Suspense fallback={<p>Завантаження...</p>}> <SearchResults query={deferredQuery} /> </Suspense> </> ); }

Що відбувається:

  1. Користувач швидко вводить текст (query оновлюється миттєво).
  2. React не поспішає оновлювати важкий компонент (SearchResults) для кожного символу.
  3. Він призупиняє оновлення deferredQuery, поки не стане "вільним".
  4. Щойно користувач перестав активно вводити -> React оновлює deferredQuery.

У результаті:

  • поле вводу залишається відзивчивим;
  • дорогі обчислення і запити не блокують UI.

2. Поведінка на практиці

ПодіяquerydeferredQueryЩо робить React
Користувач набирає "React"швидко змінюється: R -> Re -> Rea -> ...залишається позадуReact рендерить тільки input
Користувач зупинивсяназдоганяє queryзавантажує дані для "React"

3. Відмінність від startTransition()

ХукЩо робить
useDeferredValue(value)відкладає використання значення (реактивна версія)
startTransition(callback)відкладає виконання оновлення стану

Приклад еквівалентної поведінки:

javascript
// варіант зі startTransition import { startTransition } from 'react'; function onChange(e) { const value = e.target.value; setImmediateQuery(value); // оновлюємо швидко (input) startTransition(() => setDeferredQuery(value)); // відкладено - пошук }

useDeferredValue() робить те саме, але декларативно:

javascript
const deferredQuery = useDeferredValue(query);

4. Типові кейси використання

КейсЩо робить useDeferredValue
Пошуквідкладає оновлення списку результатів, щоб ввід не лагав
Великі спискионовлює рендер списку трохи пізніше, щоб UI залишався відзивчивим
Suspense-завантаження данихдозволяє показувати старі дані, поки нові підвантажуються
Фільтри / сортуванняне перерендерює таблицю при кожному кліку
Графіки і візуалізаціярендерить оновлення тільки коли React "вільний"

5. Приклад з візуальним ефектом (висока навантаженість)

javascript
function HeavyList({ filter }) { const items = Array.from({ length: 5000 }, (_, i) => `Елемент ${i}`); const filtered = items.filter(i => i.toLowerCase().includes(filter.toLowerCase())); return ( <ul>{filtered.map(i => <li key={i}>{i}</li>)}</ul> ); } export function Search() { const [filter, setFilter] = useState(''); const deferredFilter = useDeferredValue(filter); return ( <> <input value={filter} onChange={e => setFilter(e.target.value)} placeholder="Фільтр..." /> <HeavyList filter={deferredFilter} /> </> ); }

При швидкому введенні:

  • поле вводу реагує миттєво (рендер "не блокується");
  • список оновлюється з невеликою затримкою (трохи пізніше).

6. Як це працює "під капотом"

useDeferredValue:

  • повертає "затриману копію" значення;
  • позначає оновлення, що залежать від нього, як незначні (low priority);
  • React виконує ці оновлення тільки коли UI вільний;
  • якщо під час очікування приходить нове значення - старе ігнорується.

Це частина React Concurrent Rendering - нового механізму, де React сам вирішує, що оновити спочатку, а що почекає.


ПІДСУМОК

Що робитьНавіщо потрібно
Відкладене оновлення значеннязапобігає лагам при частих оновленнях
Не блокує ввід і швидкі оновленняUI залишається відзивчивим
Дозволяє плавно працювати з Suspenseстарі дані залишаються на екрані
Використовує низький пріоритет рендераReact робить "розумний" план оновлень
Чудово підходить для пошуку, фільтрів, списківзменшує зайві запити і рендери

Коротко:

useDeferredValue() - це спосіб сказати React: "Ось нове значення, але не поспішай з його рендером - онови, коли буде час."

Він робить інтерфейс плавним і відзивчивим, особливо при асинхронному завантаженні даних або рендері важких компонентів.

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

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

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