Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як зробити оптимістичне оновлення з відкатом через TanStack Query?

Оптимістичне оновлення - показати результат дії одразу, не чекаючи відповіді сервера, і відкотити, якщо сервер повернув помилку. Інтерфейс відчувається миттєвим: «лайк», позначка завдання, перейменування.

Варіант через кеш запиту:

const queryClient = useQueryClient();

const toggleTodo = useMutation({
  mutationFn: (todo) =>
    fetch(`/api/todos/${todo.id}`, { method: 'PATCH', body: JSON.stringify({ done: !todo.done }) }),

  onMutate: async (todo) => {
    await queryClient.cancelQueries({ queryKey: ['todos'] });          // 1
    const previous = queryClient.getQueryData(['todos']);               // 2
    queryClient.setQueryData(['todos'], (old) =>                        // 3
      old.map((t) => (t.id === todo.id ? { ...t, done: !t.done } : t)),
    );
    return { previous };
  },

  onError: (error, todo, context) => {
    queryClient.setQueryData(['todos'], context.previous);              // 4
    toast.error('Не вдалося зберегти');
  },

  onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }), // 5
});

Кроки й навіщо кожен:

  1. скасувати поточні запити списку - інакше відповідь, що вже летить, перезапише оптимістичні дані старими;
  2. зберегти знімок для відкату;
  3. оновити кеш - інтерфейс змінюється миттєво;
  4. при помилці - відкотити до знімка і повідомити користувача;
  5. після завершення - перезапитати дані з сервера, щоб кеш точно відповідав реальності.

Простіший варіант - через змінні мутації: не чіпати кеш, а в компоненті показувати mutation.variables, поки мутація в стані isPending. Менше коду, відкат автоматичний (просто зникає тимчасове відображення), але зміна видна лише там, де рендериться мутація.

React 19 useOptimistic - схожа ідея для дій і форм без бібліотеки: тимчасовий стан, що діє до завершення асинхронної дії.

Коли оптимізм доречний: дія майже завжди успішна, легко відкочується і не має незворотних наслідків.

Коли ні: оплати, відправка листів, видалення без можливості відновлення, операції з високим шансом відмови через валідацію - там краще чесний стан «Зберігаємо...».

Пастки:

  • кілька швидких мутацій однієї сутності: відкат однієї може затерти іншу - враховувати це при розробці onError (чи серіалізувати мутації);
  • згенеровані сервером поля (id, дати) в оптимістичному записі - тимчасові значення, які замінить відповідь;
  • повідомлення про відкат обов'язкове - тихе «повернення» стану користувач сприйме як баг.

Докладніше в документації: TanStack Query: оптимістичні оновлення

Схожі питання