Перейти к содержимому

5. Query: useMutation

Мутации — это операции, которые изменяют данные на сервере: создание, обновление, удаление. В отличие от useQuery (который работает автоматически), useMutation выполняется вручную.

const mutation = useMutation({
mutationFn: (newUser: NewUser) => createUser(newUser),
onSuccess: (data) => {
console.log('Пользователь создан:', data)
},
onError: (error) => {
console.error('Ошибка:', error.message)
},
onSettled: () => {
// Выполняется всегда: и при успехе, и при ошибке
queryClient.invalidateQueries({ queryKey: ['users'] })
},
})

useMutation возвращает два метода для вызова мутации:

mutate — синхронный вызов, не возвращает Promise:

mutation.mutate({ name: 'Анна', email: '[email protected]' })

mutateAsync — асинхронный вызов, возвращает Promise:

try {
const user = await mutation.mutateAsync({ name: 'Анна', email: '[email protected]' })
console.log('ID нового пользователя:', user.id)
} catch (error) {
console.error(error)
}

Используйте mutateAsync, когда нужно дождаться результата для следующих действий.

КоллбэкКогда вызываетсяАргументы
onMutateДо выполнения запросаvariables
onSuccessПри успехеdata, variables, context
onErrorПри ошибкеerror, variables, context
onSettledВсегда после завершенияdata?, error?, variables, context
const mutation = useMutation({
mutationFn: updateUser,
onMutate: (variables) => {
// Оптимистичное обновление UI (до ответа сервера)
return { previousData: queryClient.getQueryData(['users']) }
},
onSuccess: (data, variables, context) => {
// data — ответ сервера
// variables — то, что передали в mutate()
// context — то, что вернул onMutate
},
onError: (error, variables, context) => {
// Откат изменений при ошибке
queryClient.setQueryData(['users'], context.previousData)
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['users'] })
},
})
const {
mutate,
mutateAsync,
isPending, // true пока запрос выполняется
isSuccess, // true после успешного выполнения
isError, // true при ошибке
isIdle, // true до первого вызова
data, // данные ответа при успехе
error, // объект ошибки
reset, // сброс состояния мутации
} = useMutation({ mutationFn })

Лучшая практика — инвалидировать связанные запросы после мутации:

const queryClient = useQueryClient()
const addUser = useMutation({
mutationFn: createUser,
onSuccess: () => {
// Перезагрузить список пользователей
queryClient.invalidateQueries({ queryKey: ['users'] })
},
})