Episode ini mengajarkan langkah setup pertama yang benar: membuat QueryClient dengan default options, membungkus aplikasi dengan QueryClientProvider, dan mengatur konfigurasi global seperti staleTime, retry, refetchOnWindowFocus, serta gcTime.

Di episode 2 kalian sudah punya model mental arsitektur. Sekarang saatnya menulis kode sungguhan. Langkah pertama yang benar menentukan kenyamanan semua episode berikutnya: menyiapkan QueryClient sebagai pusat cache, membungkus aplikasi dengan QueryClientProvider, dan mengatur konfigurasi global agar perilaku semua query konsisten sejak awal.
Episode 3 membahas ketiganya secara praktis. Di akhir episode, aplikasi kalian sudah siap menerima hooks useQuery di episode 4.
QueryClient adalah wadah cache dan konfigurasi. Biasanya dibuat sekali di level aplikasi dan disimpan di variabel module:
import { QueryClient } from "@tanstack/react-query"
export const queryClient = new QueryClient()Membuat instance di luar komponen berarti cache dibagikan ke seluruh aplikasi dan tidak dibuat ulang saat render. new QueryClient() di atas menghasilkan instance dengan konfigurasi default bawaan library.
Kalian bisa langsung memberikan default options saat pembuatan. Ini pola yang umum dipakai di aplikasi nyata:
import { QueryClient } from "@tanstack/react-query"
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000,
retry: 2,
refetchOnWindowFocus: true,
gcTime: 10 * 60 * 1000,
},
},
})Konfigurasi defaultOptions.queries.staleTime diterapkan ke semua query yang tidak mengatur staleTime-nya sendiri. staleTime: 5 * 60 * 1000 berarti data dianggap segar selama 5 menit.
Agar semua hooks bisa mengakses QueryClient, bungkus aplikasi dengan QueryClientProvider. Di project Vite, ini dilakukan di src/main.tsx:
import { QueryClientProvider } from "@tanstack/react-query"
import { queryClient } from "./query-client"
import { App } from "./App"
function Main() {
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
)
}Provider menerima prop client yang berisi instance QueryClient. QueryClientProvider client={queryClient} membuat cache dapat diakses dari komponen mana pun di dalam pohon.
Aturan sederhana: buat satu QueryClient dan satu QueryClientProvider di root aplikasi. Membuat instance di dalam komponen akan membuat cache baru setiap render — itu bug yang umum dan sering sulit ditemukan.
Warning
Jangan panggil new QueryClient() di dalam komponen atau di dalam render function. Cache akan di-reset terus menerus dan semua fitur caching TanStack Query mati. Simpan instance di module scope seperti contoh di atas.
Mengatur berapa lama data dianggap segar. Nilai 0 (default) membuat data langsung basi setiap kali komponen mount. Untuk aplikasi yang datanya jarang berubah, naikkan ke 30 detik, 5 menit, atau lebih lama. Trade-off-nya: staleTime besar mengurangi jumlah request tapi data bisa ketinggalan dari server.
Berapa kali query gagal dicoba ulang. Default TanStack Query adalah 3 kali dengan jeda yang meningkat. Untuk operasi read yang penting, pertahankan nilai default; untuk query yang memang sering gagal karena input user, bisa diturunkan ke 1.
Saat user kembali ke tab browser, TanStack Query secara default me-refetch query yang basi. Ini fitur yang sangat berguna — data selalu segar saat user kembali. Atur ke false jika aplikasi kalian butuh kontrol penuh.
Berapa lama cache bertahan di memori setelah tidak ada observer. Default v5 adalah 5 menit (5 * 60 * 1000). Nilai yang lebih besar membuat data bertahan lebih lama saat berpindah-pindah halaman, dengan harga penggunaan memori.
staleTime → 0 detik
retry → 3 kali
refetchOnWindowFocus → true
gcTime → 5 menit
structuralSharing → trueRingkasan staleTime → 0 detik menunjukkan default bawaan v5. Ingat-ingat angka ini karena akan sering kita sebut sebagai baseline di episode-episode berikutnya.
Dengan provider terpasang dan konfigurasi global diatur, struktur akhir aplikasi kalian menjadi:
// src/query-client.ts
import { QueryClient } from "@tanstack/react-query"
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000,
retry: 2,
refetchOnWindowFocus: true,
gcTime: 10 * 60 * 1000,
},
},
})Satu file untuk instance dan konfigurasi, satu provider di root, dan seluruh aplikasi siap memakai cache yang konsisten. Pola pemisahan file seperti ini juga menjadi cikal bakal arsitektur folder yang akan kita bahas di episode 21.
Episode 3 menyelesaikan fondasi instalasi: membuat QueryClient dengan default options di module scope, membungkus aplikasi dengan QueryClientProvider, dan memahami konfigurasi global seperti staleTime, retry, refetchOnWindowFocus, serta gcTime.
Inti yang harus dibawa pulang:
QueryClient sekali di module scope, bukan di dalam komponen.QueryClientProvider.defaultOptions.queries menjadi konfigurasi baseline semua query.staleTime 0, retry 3, gcTime 5 menit.staleTime dan gcTime adalah dua hal yang berbeda dan harus disetel sadar.QueryClient, satu provider.Di episode 4 selanjutnya kita akan membahas useQuery dasar — membuat query pertama dengan queryKey dan queryFn, membaca status data, isLoading, isError, dan isFetching, serta pola query function yang benar. Di sinilah kalian benar-benar merasakan perbedaan dengan pola useEffect manual.