Mengelola State di React dengan Efektif
Manajemen state adalah salah satu topik paling kompleks dalam pengembangan React. Setiap aplikasi memiliki kebutuhan yang berbeda, dan tidak ada solusi tunggal yang cocok untuk semua.
Hierarki Manajemen State
+-------------------------------------------------------------+
| TINGKAT KEBUTUHAN |
| |
| +---------------------------------------------------+ |
| | 5. Global State (Zustand/Redux) | |
| | Data: Auth, Cart, Notifikasi | |
| +---------------------------------------------------+ |
| |
| +---------------------------------------------------+ |
| | 4. Server State (TanStack Query/SWR) | |
| | Data: API responses, Caching, Auto-refetch | |
| +---------------------------------------------------+ |
| |
| +---------------------------------------------------+ |
| | 3. Context API | |
| | Data: Theme, Locale, User Preferences | |
| +---------------------------------------------------+ |
| |
| +---------------------------------------------------+ |
| | 2. Lifting State Up | |
| | Data: Shared antar sibling components | |
| +---------------------------------------------------+ |
| |
| +---------------------------------------------------+ |
| | 1. Local State (useState) | |
| | Data: Form input, Toggle UI, Tab aktif | |
| +---------------------------------------------------+ |
| |
| MULAI DARI SINI — gunakan yang paling sederhana dulu! |
+-------------------------------------------------------------+
1. Local State dengan useState
Gunakan untuk data yang hanya dibutuhkan satu komponen:
import { useState } from "react";
export default function ContactForm() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [submitted, setSubmitted] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await fetch("/api/contact", {
method: "POST",
body: JSON.stringify({ name, email }),
});
setSubmitted(true);
};
// ...render form
}
2. Lifting State Up
Ketika dua komponen sibling butuh data yang sama, pindahkan state ke parent:
// Parent: menyimpan state, menurunkan ke child
function Dashboard() {
const [search, setSearch] = useState("");
return (
<>
<SearchBar value={search} onChange={setSearch} />
<ProjectList filter={search} />
</>
);
}
3. Context API
Hindari props drilling dengan Context:
// app/contexts/ThemeContext.tsx
"use client";
import { createContext, useContext, useState } from "react";
type Theme = "dark" | "light";
const ThemeContext = createContext<{
theme: Theme;
toggle: () => void;
} | null>(null);
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>("dark");
return (
<ThemeContext.Provider value={{ theme, toggle: () => setTheme(t => t === "dark" ? "light" : "dark") }}>
{children}
</ThemeContext.Provider>
);
}
4. Server State — Yang Paling Sering Disalahgunakan
JANGAN simpan data API di global state! Gunakan library khusus:
// ❌ SALAH: Simpan data API di Redux
dispatch(setPosts(data)); // Manual caching, manual loading state
// ✅ BENAR: Gunakan TanStack Query
import { useQuery } from "@tanstack/react-query";
function BlogList() {
const { data, isLoading, error } = useQuery({
queryKey: ["posts"],
queryFn: () => fetch("/api/posts").then(r => r.json()),
});
// Dapat caching, auto-refetch, loading/error state GRATIS!
}
5. Global State (Zustand/Redux)
Hanya untuk data yang benar-benar global. Zustand adalah pilihan ringan:
// store/auth-store.ts
import { create } from "zustand";
interface AuthStore {
user: { name: string; email: string } | null;
login: (user: { name: string; email: string }) => void;
logout: () => void;
}
export const useAuthStore = create<AuthStore>((set) => ({
user: null,
login: (user) => set({ user }),
logout: () => set({ user: null }),
}));
Tabel Keputusan
| Situasi | Solusi | Alasan |
|---|---|---|
| Form input, toggle, tab | useState | Hanya lokal, sederhana |
| Dua komponen sibling share data | Lifting state up | Tidak perlu eksternal |
| Tema, locale, user preferences | Context API | Jarang berubah |
| Data dari API | TanStack Query | Caching, refetch, dll gratis |
| Auth, cart, notifikasi global | Zustand | Ringan, simpel |
| Aplikasi kompleks dengan banyak state | Redux Toolkit | DevTools, middleware |
Kesimpulan: Mulailah dari yang paling sederhana (useState). Tambahkan kompleksitas hanya ketika benar-benar dibutuhkan. Jangan over-engineering!