Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Use useSWRMutation para mutações remotas (POST, PUT, DELETE) e mutate para atualizações de cache local. Combine ambos para padrões de UI otimistas que atualizam instantaneamente e reconciliam com o servidor.
"use client";
import useSWRMutation from "swr/mutation";
async function createPost(url: string, { arg }: { arg: { title: string; body: string } }) {
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(arg),
});
return res.json();
}
function NewPostForm() {
const { trigger, isMutating } = useSWRMutation("/api/posts", createPost);
const handleSubmit = async (formData: FormData) => {
await trigger({
title: formData.get("title") as string,
body: formData.get("body") as string,
});
};
return (
<form action={handleSubmit}>
<input name="title" required />
<textarea name="body" required />
<button disabled={isMutating}>
{isMutating ? "Criando..." : "Criar Post"}
</button>
</form>
);
}"use client";
import useSWR, { useSWRConfig } from "swr";
import useSWRMutation from "swr/mutation";
interface Todo {
id: number;
text: string;
done: boolean;
}
const fetcher = (url: string): Promise<Todo[]> => fetch(url).then((r) => r.json());
async function toggleTodo(url: string, { arg }: { arg: { id: number; done: boolean } }) {
return fetch(`${url}/${arg.id}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ done: arg.done }),
}).then((r) => r.json());
}
export default function TodoList() {
const { data: todos, mutate } = useSWR<Todo[]>("/api/todos", fetcher);
const { trigger } = useSWRMutation("/api/todos", toggleTodo);
const handleToggle = async (todo: Todo) => {
const newDone = !todo.done;
// Atualização otimista
await mutate(
async (current) => {
await trigger({ id: todo.id, done: newDone });
return current?.map((t) => (t.id === todo.id ? { ...t, done: newDone } : t));
},
{
optimisticData: todos?.map((t) =>
t.id === todo.id ? { ...t, done: newDone } : t
),
rollbackOnError: true,
revalidate: false,
}
);
};
return (
<ul>
{todos?.map((todo) => (
<li key={todo.id} onClick={() => handleToggle(todo)}>
<span style={{ textDecoration: todo.done ? "line-through" : "none" }}>
{todo.text}
</span>
</li>
))}
</ul>
);
}useSWRMutation é projetado para mutações que não devem ser executadas automaticamente. Ele retorna uma função trigger que você chama manualmente.trigger recebe um arg que é passado para sua função de mutação como { arg }.mutate de useSWR) é escopado para a chave do hook. Ele atualiza o cache local para essa chave específica.useSWRConfig) pode atualizar qualquer chave de cache de qualquer lugar do seu aplicativo.optimisticData atualiza imediatamente o cache antes que a mutação assíncrona seja resolvida.rollbackOnError: true reverte a atualização otimista se a mutação lançar um erro.revalidate: false pula a revalidação após a mutação quando você confia na atualização local.mutate global para invalidar chaves relacionadas:
import { useSWRConfig } from "swr";
function AddComment({ postId }: { postId: string }) {
const { mutate } = useSWRConfig();
const handleAdd = async (text: string) => {
await fetch(`/api/posts/${postId}/comments`, {
method: "POST",
body: JSON.stringify({ text }),
});
// Revalidar múltiplas chaves
mutate(`/api/posts/${postId}`);
mutate(`/api/posts/${postId}/comments`);
};
}Mutações com dados retornados:
const { trigger } = useSWRMutation("/api/posts", createPost, {
onSuccess(data) {
// data é o valor de retorno de createPost
console.log("Criado:", data.id);
},
});Popular cache após a mutação:
const { trigger } = useSWRMutation("/api/posts", createPost, {
populateCache: (newPost, currentPosts) => [...(currentPosts ?? []), newPost],
revalidate: false,
});useSWRMutation<Data, Error, Key, Arg> aceita quatro genéricos para segurança de tipo completa.(key: Key, options: { arg: Arg }) => Promise<Data>.const { trigger } = useSWRMutation<Todo, Error, string, { text: string }>(
"/api/todos",
async (url, { arg }) => {
const res = await fetch(url, {
method: "POST",
body: JSON.stringify(arg),
});
return res.json();
}
);
// trigger({ text: "Comprar leite" }) - totalmente tipadouseSWRMutation e useSWR usam o mesmo cache. Se ambos usarem a mesma chave, eles compartilham dados. Isso geralmente é o que você deseja, mas esteja ciente de que o trigger de useSWRMutation pode sobrescrever os dados em cache de useSWR.optimisticData deve ser o estado novo completo, não uma atualização parcial. Se você tem uma lista, precisa retornar a lista atualizada inteira.rollbackOnError: true, uma mutação falha deixa dados otimistas obsoletos no cache.isMutating permanece true até que a promessa trigger seja resolvida. Se você navegar para longe antes que ela seja resolvida, não haverá limpeza a menos que o componente seja desmontado.mutate() sem argumentos revalida a chave re-buscando os dados. Chamar mutate(newData) define os dados sem revalidação.| Abordagem | Prós | Contras |
|---|---|---|
| useSWRMutation | Projetado especificamente, integra-se com o cache | Requer importação separada |
| mutate vinculado + fetch | Mais simples para atualizações básicas de cache | Tratamento manual de erros |
| React Query useMutation | Mais retentativas e hooks de ciclo de vida integrados | Biblioteca diferente |
| Server Actions (Next.js) | Sem JS no cliente, nativo para formulários | Sem UI otimista sem trabalho extra |
useSWRMutation é para mutações remotas (POST, PUT, DELETE) acionadas manualmente via trigger.mutate de useSWR (vinculado) atualiza o cache local para uma chave específica.mutate global de useSWRConfig pode atualizar qualquer chave de cache de qualquer lugar.O argumento passado para trigger(arg) está disponível na função de mutação como { arg }:
async function createPost(url: string, { arg }: { arg: { title: string } }) {
return fetch(url, {
method: "POST",
body: JSON.stringify(arg),
}).then((r) => r.json());
}
const { trigger } = useSWRMutation("/api/posts", createPost);
await trigger({ title: "Olá" });optimisticData atualiza imediatamente o cache antes que a mutação assíncrona seja resolvida. Deve ser o estado novo completo (por exemplo, a lista atualizada inteira), não uma atualização parcial, porque o SWR substitui a entrada inteira do cache por ele.
Se a mutação falhar, os dados otimistas obsoletos permanecem no cache permanentemente. A UI mostrará dados que não correspondem ao estado do servidor. Sempre defina rollbackOnError: true ao usar optimisticData.
Use o mutate global de useSWRConfig:
const { mutate } = useSWRConfig();
mutate(`/api/posts/${postId}`);
mutate(`/api/posts/${postId}/comments`);Ela permite que você atualize o cache diretamente com o valor de retorno da mutação sem um fetch de revalidação:
const { trigger } = useSWRMutation("/api/posts", createPost, {
populateCache: (newPost, currentPosts) => [...(currentPosts ?? []), newPost],
revalidate: false,
});Sim. Se ambos usarem a mesma chave, eles compartilham dados em cache. O trigger de useSWRMutation pode sobrescrever dados que useSWR está exibindo. Isso geralmente é intencional, mas pode causar surpresas inesperadas.
isMutating permanece true até que a promessa trigger seja resolvida. Se o componente for desmontado antes da resolução, não haverá limpeza. Tenha cuidado com a navegação durante mutações em andamento.
const { trigger } = useSWRMutation<Todo, Error, string, { text: string }>(
"/api/todos",
async (url, { arg }) => {
const res = await fetch(url, {
method: "POST",
body: JSON.stringify(arg),
});
return res.json();
}
);
// trigger({ text: "Comprar leite" }) é totalmente tipadoA assinatura é (key: Key, options: { arg: Arg }) => Promise<Data>. Os quatro genéricos em useSWRMutation<Data, Error, Key, Arg> controlam os tipos para dados de retorno, erro, chave e o argumento passado para trigger.
mutate() sem argumentos revalida re-buscando do servidor.mutate(newData) define os dados do cache diretamente sem re-buscar.Revisado por Chris St. John·Última atualização: 10 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥