ViraStack
  • Akademi
  • Hakkında
  • Destek
Genel BakışKaynaklarKatkı
ViraStack

Frontend ekosistemi: ücretsiz rehberler, proje şablonları, AI kuralları ve form bileşenleri.

Ürünler

  • ViraStack Start
  • ViraStack AI
  • ViraStack Mask
  • ViraStack Password
  • ViraStack Guide

Keşfet

  • Akademi
  • Hakkında
  • Marka
  • Destek

© 2026 ViraStack.

Açık kaynak · MIT

TanStack Query

06 / 12

Mutation ve invalidation

useMutation, yazma işleminden sonra cache'i geçersiz kılmak ya da cevapla güncellemek, callback'lerin yeri ve global invalidation.

useMutation

Sorgular veriyi okur; sunucudaki veriyi değiştiren işlemler (ekleme, güncelleme, silme) için useMutation kullanılır.1 TkDodo farkı tek cümleyle anlatır: useQuery bildirimseldir, useMutation emirseldir. Sorgu kendiliğinden çalışır; mutation siz mutate çağırana kadar bekler.2

import { useMutation } from "@tanstack/react-query";

type StockUpdate = { productId: number; stock: number };

async function updateStock({ productId, stock }: StockUpdate): Promise<Product> {
  const response = await fetch(`/api/products/${productId}`, {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ stock }),
  });
  if (!response.ok) throw new Error(`Request failed: ${response.status}`);
  return response.json();
}

export function StockForm({ productId }: { productId: number }) {
  const mutation = useMutation({ mutationFn: updateStock });

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const stock = Number(new FormData(event.currentTarget).get("stock"));
        mutation.mutate({ productId, stock });
      }}
    >
      <input name="stock" type="number" min={0} />
      <button disabled={mutation.isPending}>Kaydet</button>
      {mutation.isError && <p>Hata: {mutation.error.message}</p>}
    </form>
  );
}

Bir mutation idle, pending, error ya da success durumundadır. mutate yalnızca tek değişken alır; birden fazla değer için bir nesne verin. Varsayılan olarak hata alan mutation tekrar denenmez.12

Mutation'dan Sonra Cache

Stok güncellendi ama ürün listesi hâlâ eski stoğu gösteriyor. Cache'i güncel hale getirmenin iki yolu var:2

YolNasılNe zaman
Invalidationİlgili sorguları eski işaretle, sunucudan yeniden çekVarsayılan tercih; sunucunun hesapladığı her şey (sıralama, toplam) doğru gelir
Doğrudan güncellemeMutation cevabını setQueryData ile cache'e yazSunucu güncel nesneyi zaten döndürüyorsa, ek istekten kaçınmak için

Invalidation

invalidateQueries, verilen anahtarla başlayan tüm sorguları eski sayar:34

const queryClient = useQueryClient();

const mutation = useMutation({
  mutationFn: updateStock,
  onSuccess: () =>
    queryClient.invalidateQueries({ queryKey: productQueries.all() }),
});

Invalidation her eşleşen sorguyu yeniden çekmez. Yalnızca ekranda olan (active) sorgular hemen yenilenir; diğerleri eski işaretlenir ve bir dahaki kullanımda yenilenir. Filtreli on farklı liste cache'te dursa bile yalnızca görüneni için istek gider.5

Callback'ten Promise'i döndürmek önemlidir. Döndürürseniz mutation, yenileme bitene kadar pending kalır ve buton yeni veri gelene kadar devre dışı durur:32

// ❌ Promise kaybolur; buton yeni veri gelmeden açılır
onSuccess: () => {
  queryClient.invalidateQueries({ queryKey: productQueries.all() });
},

// ✅ Promise döner; mutation yenileme bitince biter
onSuccess: () => queryClient.invalidateQueries({ queryKey: productQueries.all() }),

Daha dar hedefleme için exact: true ya da predicate kullanın.4 Anahtarları genelden özele kurduysanız (bkz. useQuery ve query key) çoğu zaman ön ek yeter.

Cevapla Güncellemek

Sunucu güncellenmiş ürünü döndürüyorsa onu doğrudan detay sorgusuna yazın:6

useMutation({
  mutationFn: updateStock,
  onSuccess: (updatedProduct) => {
    queryClient.setQueryData(
      productQueries.detail(updatedProduct.id).queryKey,
      updatedProduct,
    );
  },
});

setQueryData'ya verdiğiniz updater fonksiyonu eski veriyi değiştirmemeli, yeni bir nesne döndürmelidir. Cache'teki nesneyi yerinde değiştirmek ilk başta çalışıyor gibi görünür, sonra fark edilmesi zor hatalar çıkarır.6

queryClient.setQueryData(productQueries.detail(id).queryKey, (old) =>
  old ? { ...old, stock: newStock } : old,
);

Callback'ler Nerede Durmalı

Callback'leri hem useMutation'a hem mutate'e verebilirsiniz. Önce useMutation'dakiler çalışır. mutate'e verilenler ise component mutation bitmeden kaldırılırsa hiç çalışmaz.12 TkDodo bu farkı bir kural olarak kullanır:2

  • Mantık (invalidation, cache güncelleme) useMutation callback'lerine.

  • Arayüz (yönlendirme, toast, formu sıfırlama) mutate callback'lerine. Kullanıcı sayfadan ayrıldıysa toast göstermek zaten gereksizdir.

mutation.mutate(
  { productId, stock },
  { onSuccess: () => toast.success("Stok güncellendi") },
);

v5'te callback'ler son argüman olarak bir context nesnesi alır; içinde client (QueryClient), meta ve mutationKey vardır. onMutate'in döndürdüğü değer diğer callback'lere onMutateResult olarak gelir.1

mutate mı, mutateAsync mı

mutate hiçbir şey döndürmez ve hatayı kendisi yakalar. mutateAsync bir Promise döndürür; hatayı siz yakalamazsanız unhandled promise rejection alırsınız. TkDodo'nun önerisi neredeyse her zaman mutate; mutateAsync'i yalnızca birden fazla mutation'ı aynı anda bekleyecekseniz kullanın.2

Her Mutation'dan Sonra Invalidation

Her useMutation'a ayrı invalidation yazmak yerine MutationCache'e tek bir global callback verebilirsiniz. MutationCache callback'leri useMutation'dakilerden önce çalışır:5

import { MutationCache, QueryClient } from "@tanstack/react-query";

const queryClient = new QueryClient({
  mutationCache: new MutationCache({
    onSuccess: () => {
      void queryClient.invalidateQueries();
    },
  }),
});

Burada Promise döndürülmüyor; mutation, yenilemeleri beklemeden biter. Belirli bir yenilemeyi beklemek istediğiniz mutation'da useMutation'ın kendi onSuccess'inden o invalidation'ı döndürün.5

Abartı gibi görünür ama invalidation yalnızca ekrandaki sorguları yeniden çektiği için çoğu uygulamada iyi bir dengedir. Kapsamı daraltmak için mutation'ın mutationKey'ini ya da meta alanını kullanabilirsiniz.5

Mutation ayarlarını queryOptions gibi paylaşmak için mutationOptions var:7

export const updateStockOptions = () =>
  mutationOptions({ mutationKey: ["products", "update-stock"], mutationFn: updateStock });

Kendin Dene

  • Stok formunu kurun ve kaydettikten sonra listenin güncellenmediğini görün. invalidateQueries ekleyin.

  • onSuccess'te Promise'i döndürmeyin ve butonun ne zaman tekrar aktif olduğuna bakın. Sonra döndürün.

  • Invalidation yerine setQueryData kullanın. Network sekmesinde kaç istek görüyorsunuz?

  • mutate'e bir onSuccess verin, mutation sürerken component'i kaldırın. Callback çalışıyor mu?

Detaylı Öğrenmek İçin

  • Yazı: TkDodo, "Mastering Mutations in React Query"; invalidation ve doğrudan güncelleme, callback'lerin yeri ve sık hatalar.2

  • Yazı: TkDodo, "Automatic Query Invalidation after Mutations"; global callback, mutationKey ve meta ile hedefleme.5

  • Resmi doküman: "Mutations"; durumlar, callback sırası, scope ile sıralı mutation ve offline mutation.1

Kaynaklar

  • 1DokümanTanStack Query: Mutations

    `useMutation`, durumlar, callback'lerin imzası ve sırası, `mutateAsync` ve retry.

  • 2MakaleTkDodo

    : — 9 Ekim 2021. Bildirimsel ve emirsel fark, Promise döndürmek, `mutate` ile `mutateAsync`.

  • 3DokümanTanStack Query: Invalidations from Mutations

    `onSuccess`'te invalidation ve Promise döndürmenin etkisi.

  • 4DokümanTanStack Query: Query Invalidation

    Ön ek eşleşmesi, `exact` ve `predicate`.

  • 5MakaleTkDodo

    : — 25 Mayıs 2024. `MutationCache` callback'leri ve invalidation'ın yalnızca aktif sorguları yenilemesi.

  • 6DokümanTanStack Query: Updates from Mutation Responses

    `setQueryData` ile cevabı cache'e yazmak ve immutability.

  • 7DokümanTanStack Query: TypeScript

    `mutationOptions` ile mutation ayarlarını paylaşmak.

Bu sayfayı düzenle

Son güncelleme tarihi: 21 Ekim 2026

Önceki adım05. Cache ve stale timeSonraki adım07. Optimistic update