Zustand vs Redux Toolkit: Memilih State React di 2026

Foto oleh kevin dooley on flickr
Untuk kebanyakan proyek baru tanpa investasi Redux sebelumnya, Zustand adalah pilihan default yang lebih praktis karena tidak memerlukan Provider, memiliki boilerplate yang jauh lebih sedikit, dan menghasilkan bundle yang jauh lebih kecil. Redux Toolkit tetap menang di tim besar yang membutuhkan struktur yang dipaksakan, devtools time-travel yang matang, dan lapisan pengambilan data bawaan lewat RTK Query.
Redux Toolkit mengikuti arsitektur Redux klasik, di mana satu store dibuat lalu disediakan ke pohon komponen melalui React context, yang itulah yang disiapkan oleh komponen Provider. Zustand melewati ini seluruhnya dengan mengekspos store sebagai hook biasa yang bisa diimpor dan dipanggil langsung oleh komponen mana pun, tanpa perlu pembungkusan context.
Ya, dan ini adalah pola produksi yang paling umum. TanStack Query menangani apa pun yang diambil dari API - daftar, record, state paginasi - sementara Zustand menangani state yang hanya ada di browser, seperti visibilitas modal atau form multi-langkah. Mencampur kedua tanggung jawab ini dalam satu store biasanya menyebabkan data basi atau terduplikasi.
Paket inti Zustand tidak memiliki dependensi wajib selain React, sehingga jejaknya sangat minimal. Redux Toolkit menggabungkan Immer dan Redux Thunk secara default, dan setup produksi umum menambahkan react-redux untuk binding komponen di atasnya, membuat Redux Toolkit jauh lebih berat sebelum kode pengambilan data RTK Query ditambahkan.
Hindari keduanya jika state yang dimaksud hanya dibutuhkan oleh bagian kecil dan berdekatan dari pohon komponen - komponen induk yang menyimpan state di useState dan menurunkannya lewat props lebih sederhana dan lebih mudah dipahami. Hindari juga keduanya jika state tersebut sebenarnya berasal dari respons API, karena itu seharusnya berada di lapisan caching khusus seperti TanStack Query, bukan di global client store.

Foto oleh kevin dooley on flickr
Ringkasan Utama
Untuk proyek React baru di 2026, Zustand adalah pilihan default yang masuk akal: tanpa Provider, store cukup empat baris, dan bundle kecil. Redux Toolkit tetap relevan di tim besar yang butuh struktur slice yang ketat, devtools time-travel yang matang, dan RTK Query. Apa pun pilihannya, data server sebaiknya ditangani TanStack Query, bukan disimpan di client store global.
Setiap beberapa bulan selalu muncul diskusi apakah Redux sudah mati, dan jawabannya selalu sama: tidak, tapi pilihan default untuk proyek React baru di 2026 jarang lagi jatuh ke Redux Toolkit. Zustand menjadi titik awal yang praktis bagi kebanyakan tim, sementara Redux Toolkit tetap pilihan tepat begitu aplikasi tumbuh besar dan butuh struktur yang dipaksakan di antara banyak kontributor.
Artikel ini membahas perbedaan nyata yang benar-benar berpengaruh sehari-hari: seberapa banyak kode yang harus ditulis di masing-masing library, seperti apa proses debugging dengan devtools masing-masing, seberapa besar beban yang ditambahkan ke bundle, dan kesalahan yang paling sering saya lihat - menggunakan salah satu library untuk menyimpan data yang sebenarnya berasal dari API dan seharusnya berada di lapisan caching seperti TanStack Query. Semua ini bukan soal library mana yang secara objektif lebih unggul; ini soal menyesuaikan alat dengan ukuran dan bentuk masalah yang benar-benar kamu hadapi.
Titik awal Zustand adalah fungsi biasa yang mengembalikan state beserta fungsi untuk mengubahnya. Tidak ada Provider yang perlu membungkus aplikasi, tidak ada action type yang perlu didefinisikan, dan tidak ada pemanggilan dispatch di titik pemakaian - komponen cukup memanggil store seperti hook biasa dan membaca bagian state yang dibutuhkan.
// Zustand: a full store in ~10 lines, no Provider
import { create } from "zustand";
interface CartState {
items: string[];
addItem: (item: string) => void;
clear: () => void;
}
export const useCartStore = create<CartState>((set) => ({
items: [],
addItem: (item) => set((state) => ({ items: [...state.items, item] })),
clear: () => set({ items: [] }),
}));
// Usage in a component, no wrapping context needed
function CartBadge() {
const items = useCartStore((state) => state.items);
return <span>{items.length}</span>;
}Fungsi createSlice di Redux Toolkit memangkas sebagian besar seremoni yang membuat Redux klasik menyakitkan - kamu tidak lagi menulis manual action type, action creator, atau blok switch, dan Immer memungkinkan penulisan kode yang tampak mutatif namun tetap dikonversi menjadi update immutable di baliknya. Meski begitu, kamu tetap perlu menyusun sebuah slice, mendaftarkannya ke configureStore, dan membungkus pohon komponen dengan Provider sebelum satu pun komponen bisa membacanya. Untuk fitur kecil, ini jelas lebih banyak kode dibanding satu store Zustand.
// Redux Toolkit: createSlice cuts classic Redux boilerplate,
// but you still need a slice, a typed store, and Provider wiring
import { createSlice, configureStore } from "@reduxjs/toolkit";
const cartSlice = createSlice({
name: "cart",
initialState: { items: [] as string[] },
reducers: {
addItem: (state, action) => {
state.items.push(action.payload);
},
clear: (state) => {
state.items = [];
},
},
});
export const { addItem, clear } = cartSlice.actions;
export const store = configureStore({ reducer: { cart: cartSlice.reducer } });
// App root must be wrapped in <Provider store={store}>Kedua library terhubung ke ekstensi browser Redux DevTools yang sama, tapi kedalaman integrasinya berbeda. configureStore milik Redux Toolkit menghubungkan ekstensi ini secara otomatis dengan dukungan penuh untuk time travel, replay action, dan diff state di setiap action yang di-dispatch.
Jika tim kamu sangat mengandalkan debugging time-travel untuk mereproduksi bug produksi dari dump state yang diekspor, alur kerja ini jauh lebih matang di Redux Toolkit. Middleware devtools Zustand memberi visibilitas, bukan pipeline replay yang lengkap.
Paket inti Zustand sangat kecil dan tidak memerlukan dependensi wajib selain React itu sendiri. Redux Toolkit menggabungkan configureStore, createSlice, Immer, dan Redux Thunk sekaligus, dan hampir selalu kamu tambahkan react-redux di atasnya untuk menghubungkannya ke komponen. RTK Query, jika dipakai, adalah paket tambahan lagi di atas semua itu.
| Library | Paket inti | Setup produksi umum |
|---|---|---|
| Zustand | Inti minimal, tanpa paket peer wajib selain React | Store inti plus middleware devtools dan persist opsional |
| Redux Toolkit | Menggabungkan Immer dan Redux Thunk secara default | Redux Toolkit plus react-redux untuk binding komponen |
| Redux Toolkit + RTK Query | Menambahkan lapisan pengambilan dan caching data di atasnya | Setup penuh saat RTK Query menggantikan logika fetch manual |
Kesalahan arsitektur paling umum yang saya lihat saat code review tidak ada hubungannya dengan library mana yang dipilih - melainkan menyimpan data server di dalam global client state sama sekali. Data yang diambil dari API bersifat remote, asinkron, dan bisa berubah kapan saja oleh pengguna lain, yang membuatnya berbeda secara fundamental dari state UI lokal seperti nilai form atau toggle sidebar. Tim yang menyimpan record hasil fetch di slice Zustand atau Redux biasanya akhirnya membuat sendiri flag loading, logika retry, dan invalidasi cache, yang justru adalah pekerjaan yang sudah dilakukan dengan benar oleh library pengambilan data khusus.
Dokumentasi resmi TanStack Query menegaskan garis pemisah ini secara eksplisit: library state management tradisional bekerja baik untuk client state tapi tidak dibangun untuk menangani caching, refetch di background, deduplikasi, atau staleness untuk data server. Itu adalah masalah berbeda dengan solusi yang berbeda, dan mencoba menyelesaikannya secara manual di dalam store Zustand atau slice Redux biasanya berarti membangun ulang versi yang lebih buruk dari apa yang sudah dilakukan library caching khusus.
Pembagian praktis yang bekerja baik di produksi: TanStack Query menangani apa pun yang berasal dari panggilan fetch - daftar, record, cursor paginasi - sementara Zustand atau Redux Toolkit menangani semua hal yang hanya hidup di browser, seperti visibilitas modal, state form multi-langkah, atau preferensi tema.
Redux Toolkit sendiri bahkan punya jawaban untuk masalah ini lewat RTK Query, yang dengan sengaja dibangun sebagai concern terpisah yang diletakkan di atas store, bukan dicampur ke dalam slice biasa. Pilihan desain dari tim Redux sendiri ini adalah sinyal kuat bahwa server state dan client state pantas mendapat alat yang berbeda, apa pun library client-state yang akhirnya kamu pilih.
Sebelum menggunakan salah satu library, ada baiknya bertanya apakah kamu benar-benar butuh global state. Tiga pengecekan yang saya lakukan bersama tim sebelum menambahkan dependensi baru:
Pasangan useContext dan useState, dibatasi hanya pada bagian pohon komponen yang benar-benar membutuhkannya, seringkali sudah cukup untuk satu halaman atau satu fitur. Gunakan Zustand atau Redux Toolkit ketika state memang perlu dibaca dan ditulis dari cabang pohon komponen yang tidak saling berhubungan.
Untuk proyek baru yang dimulai hari ini tanpa investasi Redux sebelumnya, Zustand adalah pilihan default yang masuk akal. Ukuran bundle yang kecil, tidak perlunya Provider, dan definisi store empat baris berarti lebih sedikit kode yang harus dirawat serta hambatan yang lebih rendah bagi kontributor baru untuk memahami di mana state disimpan.
Redux Toolkit pantas dipakai di tim dan basis kode yang lebih besar, di mana struktur slice yang dipaksakan, devtools matang dengan time-travel penuh, dan lapisan pengambilan data RTK Query yang opinionated berfungsi sebagai pagar pengaman begitu puluhan engineer menyentuh store yang sama. Ia menukar sebagian seremoni dengan konsistensi, dan di tim yang cukup besar pertukaran itu sepadan. Struktur ekstra ini juga terbayar saat onboarding: karyawan baru yang membaca basis kode Redux Toolkit bisa menebak di mana suatu state berada hanya dengan mengetahui konvensi penamaan slice, yang lebih sulit diterapkan di sekumpulan store Zustand yang dibuat secara independen tanpa lapisan konvensi tambahan dari tim itu sendiri.
Apa pun yang kamu pilih, tahan keinginan untuk memigrasikan store yang sudah berjalan baik hanya karena library baru sedang tren. Migrasi membawa risiko nyata untuk manfaat yang marjinal, kecuali setup saat ini benar-benar menimbulkan masalah terukur - onboarding yang lambat, bug state yang sering, atau ukuran bundle yang benar-benar merugikan metrik waktu muat.