Зміст
Коротко
Пошук, фільтри й автозбереження не мають надсилати запит після кожного натискання клавіші. У React для цього зручно відокремити значення, яке швидко змінюється в полі, від дії, що має спрацювати після короткої паузи.
Вихідна стаття розглядає два хуки з @reactuses/core: useDebounce повертає відкладену копію значення, а useDebounceFn відкладає виклик функції. Така обгортка прибирає ручне керування таймерами та типові помилки під час демонтування компонента.
Що сталося
У наївному варіанті обробник введення створює або перезапускає setTimeout. Для малого прикладу цього досить, але згодом код обростає посиланням на таймер, очищенням і перевірками. Будь-яку з цих частин легко пропустити, копіюючи рішення до іншого компонента.
Найпомітніші дві проблеми: користувач уже залишив сторінку, а відкладений запит усе одно надсилається, або функція бачить старе значення властивості чи стану. Причина — «знімок» оточення, який замикання зберегло на момент запуску таймера.
useDebounce(value, wait) підходить для даних. Поле введення отримує кожне нове query відразу, а ефект стежить за debouncedQuery, що оновлюється лише після завершення введення.
Для дій з аргументами призначено useDebounceFn(fn, wait). Він повертає run, cancel і flush: запланувати відкладений виклик, скасувати очікуваний виклик або виконати його негайно.
Чому це важливо
Відкладення потрібне не лише для зменшення кількості запитів. Підказки пошуку, добір адреси та перевірка форми можуть сформувати відповідь для введення, яке вже втратило актуальність. За повільного з’єднання зайва робота стає помітною й може показати застарілий результат.
Поділ стану інтерфейсу та побічної дії зберігає швидку реакцію. Якщо відкладати саме значення, прив’язане до <input>, набір тексту відчувається зламаним. Якщо ж відкласти лише пошук, поле змінюється миттєво, а сервер отримує менше корисніших запитів.
Для автозбереження важливий життєвий цикл. Після натискання «Опублікувати» варто викликати flush, щоб зберегти чернетку перед основною операцією. Після «Скасувати» потрібен cancel, інакше старий таймер може записати текст уже після рішення користувача.
Хуки також не звертаються до об’єктів браузера під час відтворення. Їх можна застосовувати в компонентах із серверним рендерингом без окремої перевірки window і без розбіжностей між серверною та клієнтською розміткою.
На практиці
Спочатку визначте, що саме слід сповільнити: значення чи команду. Це рішення зазвичай важливіше за вибір конкретної бібліотеки, адже воно задає межі стану та ефектів у компоненті.
Для поля пошуку тримайте два значення: негайний текст для інтерфейсу та відкладену версію для useEffect. Не надсилайте запит для порожнього відкладеного значення, а за потреби окремо скасовуйте сам мережевий запит.
- Для пошуку, фільтра й повзунка використовуйте
useDebounce: іншим частинам коду потрібне підсумкове змінене значення. - Для автозбереження, журналювання та обробника зміни розміру використовуйте
useDebounceFn: дії передаються аргументи. - Викликайте
cancelпри явній відмові від дії, аflush— перед надсиланням форми або операцією, якій потрібні актуальні дані. - Залишайте звичайний стан швидким: відкладати слід побічну дію, а не візуальну реакцію поля.
- Під час тривалого безперервного введення розгляньте
maxWait, щоб оновлення все ж відбувалося з обмеженим інтервалом.
Опції leading і trailing допомагають визначити момент першого та останнього виклику. Наприклад, leading: true корисна для негайної реакції на перше натискання з придушенням частих повторів, а trailing: true пасує для пошуку після завершення введення.
Не плутайте відкладення з обмеженням частоти. Для прокручування, перетягування та індикатора поступу зазвичай потрібні useThrottle або useThrottleFn: оновлення мають надходити регулярно під час руху, а не лише після повної зупинки.
Підсумок
Ручний setTimeout у React майже завжди потребує більше коду, ніж здається: слід очищати таймер, не втрачати свіжі дані й не виконувати роботу після виходу зі сторінки. Спільний хук збирає ці правила в одному місці.
useDebounce корисний, коли потрібна відкладена версія стану; useDebounceFn — коли відкласти слід саму операцію. Чіткий поділ цих сценаріїв робить пошук швидшим для користувача, автозбереження передбачуванішим, а компоненти — простішими для супроводу.

