Episode ini membahas state lokal dan hooks React di Next.js, direktif use client dan batas server-client, shared state dengan Context API, Zustand, dan TanStack Query, serta perbedaan lifecycle komponen klien dan komponen server.

Setiap aplikasi interaktif menyimpan data yang berubah: nilai input form, pilihan tab, atau data pengguna. Bagaimana data itu disimpan dan dibagikan antar komponen adalah domain state management.
Episode 7 membahas state lokal dengan hooks React, konsep direktif use client dan batas antara komponen server dan klien, shared state dengan Context API, Zustand, dan TanStack Query, serta perbedaan lifecycle kedua jenis komponen tersebut.
State lokal dipakai untuk data yang hanya dipakai satu komponen. Hook useState menyimpan nilai, dan useEffect menjalankan efek samping seperti pengambilan data di klien:
"use client"
import { useState } from "react"
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Hitungan: {count}</p>
<button onClick={() => setCount((c) => c + 1)}>Tambah</button>
</div>
)
}Komponen counter di atas adalah contoh paling sederhana state lokal. Perhatikan direktif "use client" — tanpa direktif ini, hook seperti useState tidak bisa dipakai karena komponen dianggap komponen server.
Aturan praktis state lokal: letakkan state serendah mungkin di pohon komponen. Jika hanya satu komponen yang memakai nilai, simpan di komponen itu; jika beberapa komponen berbagi, naikkan state ke induk bersama atau gunakan Context.
App Router mengeksekusi komponen di dua tempat: server dan klien. Komponen server bisa membaca data langsung dan mengirim props ke komponen klien, tapi tidak bisa memakai hooks interaktif. Komponen klien bisa memakai hooks dan menangani event, tapi kodenya ikut terkirim ke browser.
Direktif "use client" menandai batas: komponen itu dan turunannya menjadi komponen klien. Aturan praktisnya — komponen yang perlu interaktivitas diletakkan paling bawah di pohon komponen, sementara struktur dan data tetap di server component. Ini meminimalkan JavaScript yang dikirim ke browser, topik yang kita dalami di episode 15.
Direktif hanya boleh muncul di bagian paling atas file, sebelum import lain. Salah letak akan menghasilkan error kompilasi — jadi kalian tidak akan tersesat lama.
Context API memungkinkan state dibagikan tanpa mengoper props ke tiap level. Cocok untuk data global yang jarang berubah seperti tema atau bahasa:
"use client"
import { createContext, useContext, useState } from "react"
const TemaContext = createContext(null)
export function TemaProvider({ children }) {
const [tema, setTema] = useState("terang")
return (
<TemaContext.Provider value={{ tema, setTema }}>
{children}
</TemaContext.Provider>
)
}
export function useTema() {
return useContext(TemaContext)
}useTema() bisa dipanggil dari komponen mana pun di bawah TemaProvider. Context cocok untuk state yang sedikit dan jarang berubah; untuk state yang sering berubah dan besar, pertimbangkan store eksternal.
Zustand adalah library store minimal yang memakai API mirip hooks dan bekerja baik dengan React 18 dan Next.js. Cocok untuk state global yang kompleks. Sementara TanStack Query (React Query) fokus pada state data server: caching, retry, dan sinkronisasi dengan API — cocok dipadukan dengan fetching di komponen klien. TanStack Query juga menangani invalidasi: setelah mutasi berhasil, data yang di-cache bisa ditandai usang dan di-fetch ulang otomatis, mencegah tampilan menampilkan data basi. Pilihannya bergantung pada jenis state: UI state pakai Context atau Zustand, server state pakai TanStack Query.
Komponen server dirender sekali di server saat build atau per request — tidak pernah dirender ulang oleh browser dan tidak punya hooks interaktif. Komponen klien menjalani lifecycle React penuh: mount, update saat state berubah, dan unmount. Karena itu:
Memahami perbedaan ini menghindari bug klasik seperti hydration mismatch — perbedaan antara HTML server dan render awal klien — yang biasanya muncul karena komponen merender nilai acak atau waktu lokal tanpa mengikuti aturan hydration.
Selain itu, komponen server yang menerima props dari komponen klien harus bisa di-serialize: fungsi, Date, atau instance class tidak bisa dikirim sebagai props. Batasi props antar komponen pada data primitif, objek, dan array yang bisa diubah ke JSON.
Untuk menangkap data di kedua sisi, pola umum yang dipakai: komponen server mengambil data, lalu meneruskannya sebagai props ke komponen klien yang menangani interaksi. Ini meminimalkan jumlah fetch yang harus disinkronkan antara server dan klien.
Inti yang harus dibawa pulang:
Di episode 8 selanjutnya kita akan membahas configuration dan environment — konfigurasi next.config.mjs, environment variables dan secrets, optimasi gambar dan penanganan aset, serta best practices performa dan optimasi build. Aplikasi kalian mulai dirapikan untuk produksi.