Episode ini membedah arsitektur di balik TanStack: query client dan cache di Query, sistem kolom dan row model di Table, state management serta loader di Router, dan cara virtualizer mengukur viewport di Virtual.

Episode 1 sudah menjelaskan apa yang TanStack pecahkan. Sekarang masuk lebih dalam: bagaimana library ini bekerja di balik layar. Memahami arsitektur membuat kalian tidak sekadar menghafal API, tapi tahu alasan di balik setiap perilaku — misalnya kenapa query di-cache, kenapa kolom didefinisikan sebagai data, dan kenapa router memisahkan state dari komponen.
Episode 2 membedah empat arsitektur inti: query client dan cache di TanStack Query, sistem kolom dan row model di TanStack Table, state management serta loader di TanStack Router, dan cara virtualizer mengukur viewport di TanStack Virtual.
Konsep ini adalah fondasi. Di episode 3 kalian akan menyentuh kode sungguhan, dan setiap detail arsitektur yang dipelajari di sini akan terpakai sampai episode 23.
Inti TanStack Query adalah QueryClient yang menampung QueryCache. Setiap pemanggilan useQuery menciptakan sebuah Query di cache, dan komponen yang berlangganan disebut QueryObserver. Saat beberapa komponen memakai queryKey yang sama, mereka berbagi satu Query — inilah dasar deduplication.
import { QueryClient } from "@tanstack/react-query"
const queryClient = new QueryClient({
defaultOptions: {
queries: { staleTime: 30_000, retry: 1 },
},
})new QueryClient({ defaultOptions }) mengatur perilaku default semua query. staleTime: 30_000 membuat data dianggap basi setelah 30 detik, dan retry: 1 membatasi percobaan ulang saat error. Keduanya akan dibahas detail di episode 4.
Ketika komponen me-mount, observer mengecek cache: jika ada data valid, langsung dipakai tanpa fetch. Jika tidak ada atau sudah stale, query di-fetch ulang di background. Setelah selesai, hasil ditulis ke cache dan semua observer yang berlangganan di-notifikasi. Pola ini menjelaskan kenapa pindah halaman terasa instan — data sudah hangat di cache.
QueryClientProvider menyalurkan queryClient ke seluruh pohon komponen lewat React context. Tanpa provider ini, useQuery tidak tahu cache mana yang dipakai dan langsung melempar error.
TanStack Table membagi dua hal: core table yang menangani state dan logika, serta rendering yang sepenuhnya kalian kontrol. Kolom didefinisikan sebagai data lewat columnHelper, sehingga kolom bisa dibuat dinamis, diturunkan, atau diprogram.
import { createColumnHelper } from "@tanstack/react-table"
const columnHelper = createColumnHelper()
const columns = [
columnHelper.accessor("nama", { header: "Nama" }),
columnHelper.accessor("tahun", { header: "Tahun" }),
]columnHelper.accessor("nama", { header: "Nama" }) memetakan kolom ke properti nama dari data, dengan label header. Array columns ini yang nanti diteruskan ke useReactTable di episode 6.
Row model adalah mesin yang mengolah data mentah menjadi baris yang siap dirender. getCoreRowModel adalah model dasar; di episode 6 dan 9 kalian akan menambahkan model sorting, filtering, grouping, dan pagination. Setiap model membungkus model sebelumnya dalam pipeline.
TanStack Router menyusun seluruh aplikasi sebagai route tree. Setiap route adalah objek dengan path, loader, dan component. Router memegang state terpusat — termasuk current location, search params, dan loader data — lalu me-notifikasi komponen saat berubah.
import { createRootRoute, createRoute, createRouter } from "@tanstack/react-router"
const rootRoute = createRootRoute()
const routeTree = rootRoute.addChildren([])
const router = createRouter({ routeTree })createRouter({ routeTree }) menghasilkan router yang diteruskan ke RouterProvider. Seluruh tree route bersifat type-safe: URL yang salah ditolak compiler.
Saat navigasi terjadi, router memanggil loader dari route tujuan, menunggu datanya atau menampilkan pending state, lalu menampilkan komponen. Data hasil loader dibaca komponen lewat useLoaderData. Lifecycle ini membuat router tahu persis kapan harus menampilkan loading, sukses, atau error.
TanStack Virtual memakai Virtualizer untuk menentukan item mana yang terlihat dalam viewport. Virtualizer membaca posisi scroll lewat getScrollElement, menghitung rentang item yang terlihat, lalu memberi tahu berapa tinggi total area scroll.
import { useVirtualizer } from "@tanstack/react-virtual"
const virtualizer = useVirtualizer({
count: 10_000,
getScrollElement: () => parentRef.current,
estimateSize: () => 40,
})count: 10_000 menyatakan jumlah item, dan estimateSize: () => 40 adalah estimasi tinggi awal tiap item. Hanya item yang terlihat yang di-render — sisanya digantikan blok kosong dengan ukuran yang sama.
Setiap item virtual diberi start dan size. Komponen menempatkan item secara absolute menggunakan transformasi translateY sebesar nilai start. Hasilnya, scroll tetap mulus meskipun data berukuran jutaan baris — detail lengkapnya ada di episode 11.
Episode 2 membedah arsitektur empat library inti: query client dan cache di Query, core table dan row model di Table, route tree dan lifecycle loader di Router, serta virtualizer dan viewport di Virtual. Semua arsitektur ini berbagi satu pola: logika dipisahkan dari rendering.
Inti yang harus dibawa pulang:
Di episode 3 selanjutnya kita akan memulai proyek dengan TanStack — scaffold proyek Vite React-TypeScript, instalasi kelima library @tanstack/*, struktur folder, serta konfigurasi TypeScript dan ESLint. Siapkan terminal kalian, karena mulai episode 3 kita menulis kode sungguhan!