Belajar tRPC - State Management & Data Fetching Patterns
Episode 8 of 19

Belajar tRPC - State Management & Data Fetching Patterns

Episode ini menguasai state management di sisi client: pola query, mutation, invalidate, dan optimistic updates, integrasi modern dengan @tanstack/react-query, serta teknik caching, refetch, dan penanganan stale data.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

tRPC menjawab masalah tipe; React Query menjawab masalah server state. Saat keduanya digabung, kalian mendapat data fetching yang tipe-aman sekaligus caching, retry, dan sinkronisasi otomatis. Episode 8 membahas pola-pola inti: query, mutation, invalidate, optimistic updates, serta cara mengatur caching dan stale data.

Konsep ini penting karena di production, request yang sama dipanggil berkali-kali tanpa sadar — dan React Query menghematnya lewat cache.

Pola Data Fetching Dasar

Query dengan Caching Otomatis

Query hasilnya di-cache berdasarkan key yang diturunkan dari path dan input. Panggilan kedua ke procedure yang sama akan dijawab cache tanpa request baru:

Query yang di-cache
function DaftarUser() {
  const { data, isFetching, refetch } = trpc.user.list.useQuery(undefined, {
    staleTime: 30_000,
  });
 
  if (!data) return <p>Memuat...</p>;
  return (
    <div>
      <button onClick={() => refetch()}>Segarkan</button>
      {isFetching && <span>Memperbarui di latar belakang</span>}
      <ul>{data.map((u) => <li key={u.id}>{u.nama}</li>)}</ul>
    </div>
  );
}

staleTime: 30_000 membuat data dianggap segar selama 30 detik — dalam jendela itu, remount komponen tidak memicu request ulang. refetch() memaksa pengambilan ulang, dan isFetching membedakan fetch awal dengan background refetch.

Mutation dan Invalidate

Setelah mutasi, cache data lama harus dibuang. Inilah peran invalidate:

Invalidate setelah mutasi
function FormUser() {
  const utils = trpc.useUtils();
 
  const createUser = trpc.user.create.useMutation({
    onSuccess: () => {
      utils.user.list.invalidate();
    },
  });
 
  return (
    <button onClick={() => createUser.mutate({ nama: "Eka" })}>
      Tambah user
    </button>
  );
}

trpc.useUtils() (di v10 bernama useContext) memberikan akses ke cache. utils.user.list.invalidate() menandai query user.list sebagai basi, sehingga komponen yang memakainya otomatis refetch.

Optimistic Updates

Tampilkan Hasil Sebelum Server Menjawab

Optimistic update membuat UI terasa instan: tampilkan hasil seolah-olah mutasi sudah sukses, lalu rollback jika server menolak:

Optimistic update
const deleteUser = trpc.user.delete.useMutation({
  onMutate: async (deleted) => {
    const utils = trpc.useUtils();
    await utils.user.list.cancel();
 
    const sebelumnya = utils.user.list.getData();
    utils.user.list.setData(undefined, (lama) =>
      (lama ?? []).filter((u) => u.id !== deleted.id),
    );
    return { sebelumnya };
  },
  onError: (_err, _vars, ctx) => {
    if (ctx?.sebelumnya) {
      utils.user.list.setData(undefined, ctx.sebelumnya);
    }
  },
  onSettled: () => {
    utils.user.list.invalidate();
  },
});

Alurnya: onMutate membatalkan query yang berjalan dan langsung mengubah cache dengan versi tanpa user yang dihapus. Jika gagal, onError mengembalikan data sebelumnya; jika selesai, onSettled memastikan cache selaras dengan server lewat invalidate.

Kapan Memakai Optimistic Update

Gunakan untuk operasi yang user-nya terasa cepat: toggle, hapus, dan update kecil. Untuk operasi dengan validasi kompleks atau risiko data salah, lebih aman menunggu response server dan menampilkan loading state.

Caching, Refetch, dan Stale Data

Menyetel Perilaku Cache Global

Atur default di QueryClient agar konsisten di seluruh aplikasi:

QueryClient dengan default
import { QueryClient } from "@tanstack/react-query";
 
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 60_000,
      retry: 1,
      refetchOnWindowFocus: false,
      refetchOnMount: "always",
    },
  },
});

Pilihan yang perlu kalian kenal:

  • staleTime: berapa lama data dianggap segar sebelum di-fetch ulang.
  • refetchOnWindowFocus: apakah refetch saat tab kembali fokus — default true di React Query.
  • retry: jumlah percobaan ulang otomatis saat gagal.
  • gcTime: berapa lama cache tidak terpakai disimpan di memory.

Stale Data vs Data yang Sedang Fetch

React Query membedakan status dengan jelas:

  • isPending: belum ada data sama sekali.
  • isFetching: sedang mengambil data (termasuk background).
  • isStale: data sudah kedaluwarsa dan butuh refetch.

Pola praktik: tampilkan data lama sambil fetch ulang di latar belakang untuk UX yang mulus:

Data lama dengan background refetch
const { data, isFetching } = trpc.post.list.useQuery(undefined, {
  staleTime: 5_000,
});
 
if (isFetching && data) return <p>Memperbarui...</p>;

isFetching && data memungkinkan kalian memberi indikator tanpa mengosongkan layar — data yang sudah ada tetap ditampilkan.

Tip

Mulai dari staleTime kecil seperti 5 detik untuk data yang sering berubah, lalu naikkan untuk data statis. staleTime yang terlalu besar membuat user melihat data basi; terlalu kecil membuat request boros.

Penutup

Episode 8 memberi kalian kendali penuh atas server state di client: query yang di-cache, invalidate untuk menjaga sinkronisasi, optimistic updates untuk UX yang responsif, serta pengaturan caching dan stale data yang sesuai kebutuhan aplikasi.

Inti yang harus dibawa pulang:

  • Query di-cache berdasarkan path dan input secara otomatis.
  • invalidate() menandai query basi agar di-fetch ulang.
  • onMutate untuk optimistic update, onError untuk rollback.
  • staleTime mengontrol umur data; refetchOnWindowFocus mengontrol refetch.
  • isPending, isFetching, dan isStale adalah tiga status penting.
  • Optimistic update paling cocok untuk operasi yang terasa cepat.

Di episode 9 selanjutnya kita akan membahas schema evolution, versioning & backward compatibility — mengubah API tRPC tanpa memutus client, pendekatan versioning dan deprecation procedure, serta migrasi schema input dan output dengan menjaga kompatibilitas.

Belajar tRPC - State Management & Data Fetching Patterns | Belajar tRPC