Episode ini membangun model mental TanStack Query: perbedaan query dan mutation, perjalanan query key menuju cache, konsep observer, staleTime dan gcTime, structural sharing, serta komponen utama QueryClient, provider, dan hooks yang tersedia.

Sebelum menulis kode, bangun dulu model mental yang benar. TanStack Query bukan sekadar kumpulan hook — dia adalah sistem cache yang lengkap dengan alur kehidupan data yang jelas. Kalau kalian memahami arsitekturnya, semua opsi konfigurasi di episode berikutnya akan terasa masuk akal, bukan sekadar dihafal.
Episode 2 membedah dua model operasi utama (query dan mutation), cara data mengalir dari query key menuju cache, serta komponen-komponen yang membentuk library ini. Ini adalah fondasi arsitektural dari seluruh series.
Sebuah query adalah operasi baca yang identik dengan request GET. Query dideklarasikan dengan dua hal: queryKey sebagai identitas unik, dan queryFn sebagai fungsi yang mengambil data. Contoh mental modelnya:
useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
})Data hasil query disimpan di cache dengan kunci ["todos"]. Selama query yang sama digunakan di mana pun, data yang sama dibaca dari cache — tidak ada double fetch.
Sebuah mutation adalah operasi tulis — POST, PUT, PATCH, atau DELETE. Mutation tidak disimpan di cache dengan cara yang sama seperti query, karena dia hanya terjadi sekali. Tugas mutation adalah menulis data ke server, lalu memberi tahu cache agar diperbarui.
useMutation({
mutationFn: createTodo,
})Perbedaan mendasar: query bersifat deklaratif dan berulang, mutation imperatif dan sekali jalan. useMutation dipanggil lewat method mutate pada event handler, sedangkan useQuery berjalan otomatis saat komponen di-mount. Keduanya berbagi satu hal — keduanya berjalan di atas cache global yang sama.
Saat komponen memanggil useQuery, terjadi alur yang bisa diringkas dalam satu diagram:
queryKey → observer → fetch → cache → komponenqueryKey adalah input pertama: dia menentukan slot cache mana yang dibaca. Setiap query yang memakai key sama berbagi satu entri cache. Inilah yang membuat deduplication bekerja — dua komponen dengan key identik tidak melakukan dua fetch.
Setiap panggilan useQuery menciptakan observer. Jika banyak komponen memakai key yang sama, mereka semua berlangganan pada satu entri cache yang sama. Library mendeteksi ini dan hanya melakukan satu fetch untuk key tersebut, lalu membagikan hasilnya ke semua observer. Ketika satu observer di-unmount, yang lain tetap dapat data dari cache tanpa fetch baru.
Dua pengatur waktu yang paling sering disalahpahami:
Data bisa "segar tapi tidak terpakai" dan "terpakai tapi basi". Keduanya diatur terpisah, dan episode 7 akan membahasnya secara mendalam.
Saat cache diperbarui, TanStack Query tidak membuat objek baru secara membabi buta. Structural sharing memastikan bahwa bagian struktur data yang tidak berubah tetap mereferensi objek yang sama, sehingga render ulang dan memoization tetap efisien.
const a = { todos: [], meta: { page: 1 } }
const b = produce(a, (draft) => {
draft.meta.page = 2
})
a.todos === b.todos // true, array todos tidak disentuhPerbandingan a.todos === b.todos bernilai true karena structural sharing — referensi array yang tidak berubah dipertahankan. produce di atas hanya ilustrasi dari hasil akhir; mekanisme internal TanStack Query berbeda tapi efeknya sama.
QueryClient adalah tempat semua cache dan konfigurasi hidup. Dia dibuat sekali dan diberikan ke seluruh aplikasi lewat provider:
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
const queryClient = new QueryClient()
export function App() {
return (
<QueryClientProvider client={queryClient}>
<Todos />
</QueryClientProvider>
)
}new QueryClient() menciptakan satu instance cache global untuk aplikasi kalian. QueryClientProvider menyuntikkan instance itu ke seluruh pohon komponen sehingga semua hooks bisa mengaksesnya.
Di atas QueryClient, library menyediakan hooks utama:
useQuery untuk membaca satu query.useMutation untuk operasi tulis.useQueries untuk beberapa query paralel sekaligus.useInfiniteQuery untuk data yang dimuat bertahap.useQueryClient untuk mengakses QueryClient dari komponen.Semua hooks ini akan dipecah satu per satu di episode-episode berikutnya.
Terakhir, ada React Query Devtools — panel yang menampilkan seluruh cache, status tiap query, jumlah fetch, dan tombol untuk meng-invalidate secara manual. Devtools adalah mata dan telinga kalian saat debugging, dan akan dibahas detail di episode 17.
Tip
Mulai sekarang biasakan membayangkan setiap query sebagai sebuah slot di cache yang punya identitas berupa query key. Semua perilaku TanStack Query — refetch, invalidation, optimistic update — sebenarnya adalah manipulasi pada slot-slot tersebut.
Episode 2 membangun model mental arsitektur TanStack Query: query untuk membaca, mutation untuk menulis, cache global yang diidentifikasi oleh query key, observer yang melakukan deduplication, serta pengatur waktu staleTime dan gcTime yang terpisah.
Inti yang harus dibawa pulang:
queryKey menentukan slot cache; key identik berarti data dibagikan.staleTime mengatur kesegaran; gcTime mengatur pembuangan cache.QueryClient plus provider adalah jantung library ini.Di episode 3 selanjutnya kita akan membahas setup dan konfigurasi QueryClient — cara membuat instance dengan default options, membungkus aplikasi dengan QueryClientProvider, serta mengatur staleTime, retry, refetchOnWindowFocus, dan gcTime secara global. Ini langkah pertama yang benar-benar menulis kode TanStack Query.