Запрос успешен. Почему на экране неверные данные?

Иногда ошибки во frontend возникают не из-за неправильного ответа API, а из-за порядка, в котором приходят ответы.

Представим интерфейс со списком заявок.

Пользователь открывает первую заявку, а затем быстро переключается на вторую. Для каждой отправляется отдельный запрос.

Первый запрос выполняется медленно, второй – быстро.

Сначала приходят данные второй заявки и отображаются в интерфейсе. Но спустя некоторое время завершается первый запрос.

Если оба обработчика обновляют одно состояние без дополнительных проверок, устаревшие данные могут перезаписать актуальные.

В итоге оба запроса успешны, сервер вернул корректные данные, но пользователь видит не ту заявку.

Это пример race condition – состояния гонки, когда порядок завершения асинхронных операций влияет на результат.

Как с этим бороться?

1. Отменять неактуальные запросы С помощью AbortController можно отменять предыдущий fetch при переключении между заявками.

Но отмена запроса не гарантирует остановку всей последующей асинхронной обработки, если она не учитывает AbortSignal.

2. Игнорировать устаревшие результаты При ручной загрузке через useEffect можно использовать cleanup-функцию и флаг актуальности.

Перед обновлением состояния проверяем, относится ли результат к актуальному запросу. Если нет – игнорируем его.

3. Правильно работать с кэшем Здесь интересен RTK Query, с которым я работаю.

По умолчанию библиотека формирует ключ кэша на основе endpoint и аргументов запроса. Поэтому данные разных заявок хранятся отдельно.

Но есть нюанс с data и currentData.

data может содержать результат предыдущего аргумента, пока новые данные загружаются.

currentData содержит данные именно для текущего аргумента, если они доступны.

Само по себе это не race condition, а предусмотренное поведение RTK Query. Поэтому важно различать устаревший ответ запроса и отображение предыдущих данных из кэша.

Отдельный момент – тестирование.

Недостаточно проверить, что API возвращает успешный ответ.

Важно воспроизводить быстрое переключение между объектами, задержки сети и ситуации, когда старый запрос завершается последним.

И проверять не только ответы, но и то, какие данные в итоге видит пользователь.

Всё больше убеждаюсь, что корректная работа с асинхронностью — это не только получение данных, но и управление их актуальностью.

А как вы защищаетесь от race conditions? Отменяете запросы, игнорируете устаревшие результаты или полагаетесь на механизмы RTK Query и других библиотек?

Запрос успешен. Почему на экране неверные данные? | Сетка — социальная сеть от hh.ru Запрос успешен. Почему на экране неверные данные? | Сетка — социальная сеть от hh.ru