Мутації та Інвалідація: Зміна Даних
Мутації та Інвалідація: Зміна Даних
Досі ми лише читали дані (GET). Але веб-додатки — це про взаємодію. Ми хочемо створювати, оновлювати та видаляти дані (POST, PUT, DELETE).
У TanStack Query за це відповідає хук useMutation.
useMutation vs useQuery
| Характеристика | useQuery | useMutation |
|---|---|---|
| Запуск | Автоматично (декларативно) | Вручну (імперативно) |
| Призначення | Читання (Read) | Запис (Write) |
| Кешування | Кешує результат | Не кешує (зазвичай) |
| Retries | 3 рази за замовчуванням | 0 разів (зазвичай небезпечно повторювати POST) |
Анатомія Мутації
import { useMutation, useQueryClient } from '@tanstack/react-query';
function CreateTodo() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (newTodo: { title: string }) => {
return fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(newTodo),
}).then(res => res.json());
},
// Callback на успіх
onSuccess: (data) => {
console.log('Todo created!', data);
},
// Callback на помилку
onError: (error) => {
console.error('Error creating todo:', error);
},
});
return (
<button
onClick={() => {
// Запуск мутації
mutation.mutate({ title: 'Learn React Query' });
}}
disabled={mutation.isPending} // isPending замість isLoading
>
{mutation.isPending ? 'Saving...' : 'Add Todo'}
</button>
);
}
mutate vs mutateAsync
Ви отримаєте два методи для запуску мутації:
mutate(variables, { onSuccess, ... }):- Нічого не повертає (
void). - Безпечний: якщо станеться помилка, вона буде перехоплена
onErrorв налаштуваннях хука. Додаток не впаде. - Рекомендовано для 95% випадків (обробники подій onClick).
- Нічого не повертає (
mutateAsync(variables):- Повертає
Promise. - Ви повинні самі обробляти помилки через
try/catchабо.catch(). - Потрібен, якщо ви хочете чекати завершення мутації, щоб зробити щось ще (наприклад, редірект або закриття модалки).
- Повертає
// Приклад з mutateAsync
const onSubmit = async (data) => {
try {
await mutation.mutateAsync(data);
// Цей код виконається тільки після успіху
history.push('/todos');
} catch (error) {
// Обов'язково обробити помилку!
toast.error(error.message);
}
};
Інвалідація Запитів (Invalidation)
Це найпотужніша частина TanStack Query. Після того, як ми додали нову Todo, наш список ['todos'] у кеші став застарілим (там немає нового елемента).
Ми повинні сказати Query Client: "Познач ключ ['todos'] як брудний (stale)".
onSuccess: () => {
// Позначає ВСІ запити, що починаються з ['todos'], як stale.
// Query автоматично зробить refetch для тих з них, які зараз активні на екрані.
queryClient.invalidateQueries({ queryKey: ['todos'] });
}
Як це працює?
- Мутація завершується успішно.
invalidateQueriesзнаходить всі активні запити з ключем['todos'].- Він позначає їх як
stale. - Так як вони активні (компонент змонтований), Query миттєво запускає
refetchу фоні. - Користувач бачить оновлений список автоматично. Ніяких ручних
setTodos([...todos, newTodo])!
Часткове співпадіння ключів (Fuzzy Matching)
queryClient.invalidateQueries({ queryKey: ['todos'] }) інвалідує:
['todos']['todos', 1]['todos', 'list', { filter: 'done' }]
Це супер зручно. Ви просто кажете "Все, що стосується todos, застаріло".
Якщо ви хочете інвалідувати тільки точний ключ:
queryClient.invalidateQueries({
queryKey: ['todos'],
exact: true
});
Promise Await в onSuccess
Іноді вам треба дочекатися, поки refetch закінчиться (наприклад, щоб тест пройшов, або щоб закрити модалку тільки коли список оновився).
Поверніть Promise з onSuccess:
onSuccess: async () => {
// Ми чекаємо, поки invalidate завершить всі refetch
await queryClient.invalidateQueries({ queryKey: ['todos'] });
// Тепер дані точно оновлені
closeModal();
}
Обробка помилок (Side Effects)
Ви можете передавати колбеки як в useMutation (глобально для хука), так і в mutate (локально для виклику).
Порядок виконання:
useMutation.onSuccessmutate.onSuccessuseMutation.onSettledmutate.onSettled
useMutation колбеки для речей, які завжди мають статися (інвалідація кешу).
Використовуйте mutate колбеки для UI специфіки (показати тост, редірект, закрити форму).Синхронізація Даних: Життєвий Цикл Запиту
Одна з найскладніших речей для розуміння в TanStack Query — це те, як і коли він вирішує оновити дані. "Чому воно знову робить запит?", "Чому дані зникли?" — типові питання.
Оптимістичні Оновлення: Швидше за Світло
Ви коли-небудь помічали, як працює лайк в Instagram або повідомлення в Telegram? Ви натискаєте кнопку, і серце стає червоним миттєво. Додаток не чекає, поки сервер скаже "ОК". Він оптимістично припускає, що все буде добре.