Комментарий пользователя
Добрый день! При быстром вводе поискового запроса приходят несколько параллельных ответов. Иногда старый ответ даже возвращается позже и перезаписывает свежие данные. Как сделать так, чтобы в итоге отображались именно результаты последнего, самого актуального запроса?
Ответ специалиста
Здравствуйте, Максим! Такая ситуация называется гонкой запросов (race condition). Два простых и надежных подхода: отменять предыдущий запрос с AbortController, либо отслеживать порядковый номер запроса и принимать в состояние только ответ с последним номером. Первый вариант подойдет, если ваш fetch/библиотека поддерживает signal, а второй — универсален для любых async-операций.Приведу короткий пример с AbortController (эффект отменяет предыдущий fetch в cleanup):
useEffect(() => {
const ac = new AbortController();
const signal = ac.signal;
(async () => {
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`, { signal });
if (!res.ok) throw new Error('HTTP ' + res.status);
const data = await res.json();
setResults(data);
} catch (err) {
if (err.name !== 'AbortError') {
console.error(err);
setError(err);
}
}
})();
return () => ac.abort();
}, [q]);
И пример с токеном запроса. Работает всегда — даже если нельзя отменять запрос:
const latest = useRef(0);
useEffect(() => {
const id = ++latest.current;
(async () => {
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`);
const data = await res.json();
if (id === latest.current) setResults(data); // применяем только если это последний ответ
})();
}, [q]);
Проверьте в DevTools во вкладке Network, что при быстрых сменах параметра q запросы отправляются в нужном порядке. Состояние при этом обновляется только результатами самого последнего запроса. Для удобства можно включить throttling в Network, чтобы замедлить ответы и наглядно увидеть порядок их получения.
Чтобы не сталкиваться с проблемами, подписывайтесь на рассылку Академии Selectel, вас ждут — полезные новости, рабочие паттерны и советы.