Как реализовать удаление элементов из списка с учётом оптимистического обновления
Что проверяют
Понимаете ли вы, что оптимистичное обновление это не «удалить из стейта и отправить запрос», а обещание, которое иногда придётся откатывать. Смотрят, как вы откатываете, не затирая чужие изменения, и что происходит при нескольких удалениях подряд. Следом спрашивают, как это сделать в TanStack Query или через useOptimistic.
Как отвечать
Базовая схема: убрать элемент из списка сразу, отправить DELETE, при ошибке вернуть элемент и показать уведомление. Детали, которые отличают сильный ответ:
- функциональные обновления:
setItems(prev => prev.filter(i => i.id !== id)). Откат тоже черезprev, возвращая только этот элемент на его прежнее место, а не весь список из замыкания; - TanStack Query: в
onMutateвызываетеcancelQueries, чтобы летящий запрос списка не перезаписал оптимистичное состояние, сохраняете снимок черезgetQueryData, меняете кэш черезsetQueryDataи возвращаете снимок как контекст. ВonErrorоткатываетесь, вonSettledделаетеinvalidateQueries; useOptimisticв React 19: показывает оптимистичное состояние, пока идёт action, и само возвращается к подтверждённому, когда он завершился. Подходит, если мутация идёт через action или форму;- ответ 404 на удаление считайте успехом: элемента уже нет, возвращать его нечего;
- повторные клики: помечайте элемент как удаляемый и игнорируйте второй запрос по тому же
id.
Хорошо дополнить альтернативой для необратимых действий: отложенное удаление с кнопкой «Отменить» в тосте, когда запрос уходит только через несколько секунд.
Где спотыкаются
Откатываются через setItems(items), где items взят из замыкания. Если за время запроса пользователь удалил ещё два элемента, откат первого вернёт и их.
Используют в качестве key текст элемента или индекс. После удаления React путает соседние строки, и у них перескакивает состояние: раскрытость, фокус, введённый текст.
Не отменяют параллельные запросы списка. Ответ старого GET приходит после оптимистичного удаления, и элемент появляется снова без всякой ошибки.