Belajar Zustand Bagi Yang Memiliki Kedengkian Terhadap Redux

yzza 😎☝️

Nauval
Kredibel
14 min readDec 20, 2022

--

ketimpa reducer

React tidak memiliki opini apapun tentang bagaimana kita mengelola state di dalamnya. Kita bebas memilih pustaka pihak ketiga apapun yang kita inginkan untuk membantu kita dalam mengatur state di React.

Hal ini sebenarnya mudah saja, sebab banyak di luar sana pustaka pengelola state yang dapat digunakan. Kita dapat menggunakan pustaka seperti Recoil, Jotai, Rematch, atau Zustand. Iya, iya, termasuk Redux.

Tidak ada yang resmi dalam mengatur state di React kecuali React itu sendiri. Maksudnya begini, memang pencipta Redux adalah orang yang sama yang memelihara React saat ini, tapi bukan berarti Redux menjadi pustaka yang resmi untuk React dalam hal mengelola state.

Bahkan perusahaan yang sama yang membuat React juga membuat pustaka pengelola state bernama Recoil, tapi itu tidak membuatnya menjadi sesuatu yang resmi bagi React, atau sesuatu yang direkomendasikan secara otomatis.

React merupakan pustaka yang unopinionated, tidak ada cara yang “benar” di dalam React. Kita mungkin menggunakan Redux sebagai pengelola state untuk aplikasi kita, mungkin orang lain menggunakan yang lain, tidak ada yang resmi untuk hal itu, semuanya tergantung kebutuhan. Bahkan pada dasarnya menggunakan teknologi itu sesuai kebutuhan, ‘kan?

Hal semacam ini membebaskan dan sekaligus membingungkan dalam waktu yang sama. Kita memang bebas dalam hal menggunakan React, tapi kadangkala juga membingungkan mengenai cara yang kita gunakan apakah sudah “benar”.

Dalam konteks ini, saya tidak pernah protes pada cara orang menggunakan React. Sebab tidak ada cara yang mutlak. Kita tidak bisa mengukur suatu kebenaran hanya dengan ukuran kita sendiri – egosentris!

Pada dasarnya, React memiliki pengelola state sendiri. Jika menggunakan komponen class kita dapat menggunakan this.state atau jika di dalam komponen fungsi kita dapat menggunakan useState atau useReducer hook.

Pengelola-pengelola state tersebut bekerja di level komponen, artinya jika membutuhkannya pada level aplikasi (global state management), pengelola-pengelola state tersebut belum dapat menjawabnya.

Mungkin belakangan ini banyak orang yang mencoba menggabungkannya dengan Context, sebuah fitur di React untuk dependency injection. Kita dapat menggunakan pengelola state React yang tadi sebagai penyimpanannya, dan Context untuk menyebarkannya ke seluruh komponen di aplikasi React kita.

Hal ini memungkinkan untuk dilakukan. Namun, perlu diingat bahwa Context bukan sebuah fitur yang diciptakan untuk mengelola state, karena ia tidak memiliki penyimpanan dan juga algoritma untuk membedakan perubahan state. Untuk itu kita dapat menggunakan pustaka pihak ketiga dalam mengelola state dalam level aplikasi di React, seperti Redux atau Zustand.

Pada dasarnya setiap pustaka pengelola state menyelesaikan masalah utama yang sama, hanya saja cara mereka menyelesaikan masalahnya yang berbeda, sehingga menciptakan solusi yang berbeda. Cara menggunakan masing-masing pustaka pengelola state juga berbeda.

Jika berbicara tentang pustaka pengelola state untuk React, sudah pasti Redux menjadi yang nomor satu. Pada versi yang lebih purba, Redux memerlukan boilerplate yang sangat panjang agar dapat digunakan. Pada versi modernnya, Redux menjadi lebih ringkat berkat Redux Toolkit.

Bukan berarti Redux menjadi status quo, mungkin kita dapat menggunakan pengelola state yang lain seperti Zustand karena beberapa alasan.

Pertama kali saya menggunakan Zustand adalah pada saat saya menemukan Redux terlalu ribet untuk digunakan. Saya menemukan beberapa alternatif lain, namun saya bertahan pada Zustand karena cocok dengan saya yang inginnya praktis.

Selain praktis, Zustand memiliki algoritma sendiri untuk membedakan perubahan yang terjadi di dalam state. Hal ini bagian penting bagi pustaka pengelola state. Bayangkan kita memiliki beberapa jenis data di dalam sebuah state, ketika kita mengubah satu data maka ia akan memicu semua komponen untuk render ulang.

Hal ini yang membuat algoritma di dalam pengelola state menjadi penting. Ia akan menjaga agar komponen-komponen tertentu saja yang melakukan render ulang. Lebih spesifiknya adalah komponen yang mengkonsumsi data yang saat itu berubah saja yang melakukan render ulang.

Sungguh tidak masuk akal bila kita memiliki komponen sidebar yang tidak mengakses data produk di keranjang tiba-tiba melakukan render ulang, ketika pengguna menambah produk baru ke dalam kerangjang. Hal ini juga akan berpengaruh pada performa aplikasi React kita, bila sebuah komponen terlalu berat untuk di-render harus melakukan render ulang secara tidak masuk akal.

Zustand ini berbasis hook, jadi membuat pustaka ini lebih mudah digunakan ketika mengkonsumsi store yang dibuatnya. Setiap store yang dibuat dengan Zustand merupakan sebuah hook, sehingga kita dapat menggunakannya seperti hook pada umumnya.

Kita akan membahas Zustand dalam lingkup pengelola state di ekosistem React, walaupun sebenarnya Zustand dapat digunakan pada aplikasi JavaScript reguler tanpa React.

Mungkin saja Zustand dapat menjadi alternatif kamu untuk mengelola state di React dibanding dengan pustaka pengelola state lainnya.

Sebelum Memulai

Saya berasumsi bahwa kamu sudah memahami dasar-dasar React, juga sudah mempelajari Context. Paling tidak sudah paham mengapa membutuhkan pengelola state untuk level aplikasi.

Video berikut dapat dijadikan referensi:

Saya tidak akan membuat tahap-tahap yang rinci dalam tutorial ini, seperti cara memasang paket dengan pengelola paket NPM atau Yarn. Saya berasumsi kamu sudah paham hal-hal seperti ini.

Memasang Zustand

Anggap saja kamu sudah memiliki proyek React yang dibuat dengan CRA atau Vite, kamu dapat memasang Zustand dengan perintah berikut:

yarn add zustand

# menggunakan NPM
npm install zustand

Membuat Counter Dengan useState dan Zustand

Pada dasarnya membuat aplikasi counter dengan React adalah seperti ini:

import { useState } from 'react';

function App() {
const [count, setCount] = useState(0);

return (
<div>
<button onClick={() => setCount(count - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}

export default App;

Kita dapat membuat hal yang sama dengan Zustand, menjadi seperti ini:

import create from 'zustand';

const useStore = create((set) => ({
count: 0,
decrease: () => set((state) => ({ count: state.count - 1 })),
increase: () => set((state) => ({ count: state.count + 1 })),
}));

function App() {
const counter = useStore();

return (
<div>
<button onClick={counter.decrease}>-</button>
<span>{counter.count}</span>
<button onClick={counter.increase}>+</button>
</div>
);
}

export default App;

Pada kasus yang lebih nyata, kita dapat membuat sebuah store Zustand pada berkas terpisah agar dapat digunakan dalam beberapa komponen React yang berbeda.

Bagian penting pada kode di atas adalah bagian berikut:

import create from 'zustand';

const useStore = create((set) => ({
count: 0,
decrease: () => set((state) => ({ count: state.count - 1 })),
increase: () => set((state) => ({ count: state.count + 1 })),
}));

Karena bagian tersebut merupakan cara kita menggunakan Zustand atau membuat sebuah penyimpanan atau store dengan Zustand dan menaruhnya ke dalam variabel useStore .

Pada contoh di atas juga kita membuat satu data yaitu count , selain itu kita juga membuat dua buah actions atau sebuah fungsi yang bertugas untuk mengubah data pada state count. Dalam hal ini kita membuat fungsi decrease untuk mengurangi data count , dan fungsi increase untuk menambah data count . Selain itu, store tersebut juga merupakan sebuah hook, itu kenapa kita menggunakan awalan use .

Bagian penting lainnya adalah bagian berikut:

const counter = useStore();

Karena bagian tersebut merupakan cara kita menggunakan penyimpanan atau store Zustand yang kita buat sebelumnya.

Jika kita log variabel counter , maka hasilnya seperti ini:

Isi dari store

Sebenarnya kita dapat menyuplai argumen berupa fungsi ke dalam fungsi useStore untuk memilih bagian apa saja yang akan diekstrak pada store tersebut. Ini berguna ketika kita menyimpan beberapa jenis data yang berbeda dalam satu store yang sama, seperti ini:

const state = useStore((state) => ({
count: state.count,
increase: state.increase,
decrease: state.decrease,
}));

Hal ini berguna ketika kita memiliki beberapa jenis data di dalam satu store yang sama.

Sekarang kita perlu pindahkan ke dalam berkas yang berbeda bagian kode untuk membuat sebuah store Zustand, menjadi seperti ini:

import create from 'zustand';

export const useStore = create((set) => ({
count: 0,
decrease: () => set((state) => ({ count: state.count - 1 })),
increase: () => set((state) => ({ count: state.count + 1 })),
}));

Anggap saja kita menyimpannya pada lokasi ./stores/store.js .

Pada kode di atas kita mengekspor variabel useStore yang merupakan sebuah instance dari store Zustand. Dengan ini kita dapat mengimpornya pada komponen React yang lain, seperti ini:

import { useStore } from './stores/store';

function App() {
const counter = useStore();

return (
<div>
<button onClick={counter.decrease}>-</button>
<span>{counter.count}</span>
<button onClick={counter.increase}>+</button>
</div>
);
}

export default App;

Kode di atas akan membuat hasil yang sama seperti sebelumnya.

Zustand

Zustand memiliki sintaksis yang ringkas untuk memulai membuat sebuah store. Kita hanya perlu menggunakan API create dari pustaka Zustand dan menyuplai fungsi sebagai argumen create tersebut. Fungsi inilah yang mengatur bagaimana store kita dibentuk.

Fungsi yang disuplai sebagai argumen harus mengembalikan object, object tersebut yang bisa kita gunakan untuk menaruh data dan fungsi action untuk mengelola data tersebut.

create()

Untuk membantu memahaminya dengan lebih mudah, kita akan buat sebuah fungsi terpisah seperti ini:

function store(set) {
return {
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
decrease: () => set((state) => ({ count: state.count - 1 })),
};
}

export const useStore = create(store);

Pada kode di atas terdapat dua buah fungsi increase dan decrease yang bertugas untuk menambah dan mengurangi nilai pada data count . Di dalam fungsi tersebut, kita menggunakan fungsi set untuk memperbarui data pada store. Fungsi set setidaknya dapat disuplai dengan object atau fungsi seperti sebelumnya.

Kita menyuplai fungsi karena ingin mendapat nilai terkini dari data count , lalu hasilnya ditambahkan 1 atau dikurangi satu sesuai dengan tugas kedua fungsi tersebut.

Pada dasarnya kita dapat menyuplainya dengan object:

set({ count: n })

Fungsi tersebut akan melakukan merge secara otomatis dengan data state yang lain. Itu kenapa kita tidak memerlukan spread operator yang biasa kita gunakan ketika menggunakan hook useState salah satunya.

Katakanlah kita memiliki dua data: count dan count2 , seperti ini:

function store(set) {
return {
count: 0,
count2: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
decrease: () => set((state) => ({ count: state.count - 1 })),
};
}

export const useStore = create(store);

Jika kita memanggil fungsi increase atau decrease , maka kita tidak perlu memberitahu Zustand untuk mempertahankan data count2 . Karena pada dasarnya, Zustand akan membiarkan state yang tidak berubah. Kita tidak perlu melakukan hal seperti ini:

set((state) => ({ ...state, count: state.count + 1 }))

Karena fungsi set melakukan merge secara bawaan, kita dapat memberitahu fungsi tersebut untuk menimpa keseluruhan state dengan menyuplai true pada argumen kedua, seperti ini:

set({}, true)

Hal ini akan membuat Zustand menimpa keseluruhan state di dalam store dengan nilai yang kita suplai pada argumen pertama, dalam hal ini adalah object kosong. Penting dicatat, state yang dimaksud di sini bukan hanya data seperti count saja, melainkan termasuk fungsi action juga akan ikut ditimpa. Itu artinya dengan kode di atas, kita akan menghapus seluruh state termasuk semua action di dalamnya.

Selain set, sebenarnya fungsi store dapat menerima parameter lain, yaitu get . Fungsi ini dapat kita gunakan untuk mengakses state di dalam action. Kita dapat menulis ulang kedua action sebelumnya menjadi seperti ini:

function store(set, get) {
return {
count: 0,
increase: () => set({ count: get().count + 1 }),
decrease: () => set({ count: get().count - 1 }),
};
}

export const useStore = create(store);

Karena action di dalam store adalah fungsi reguler, itu berarti kita dapat memberikan parameter di dalamnya. Misal, kita ingin mengubah angka 1 menjadi dinamis sesuai dengan argumen yang disuplai.

function store(set, get) {
return {
count: 0,
increase: (n) => set({ count: get().count + n }),
decrease: (n) => set({ count: get().count - n }),
};
}

export const useStore = create(store);

Dengan seperti itu, kita dapat menyuplai argumen n pada kedua action tersebut. Sehingga penggunannya menjadi seperti ini:

increase(2)

decrease(2)

Kita dapat membuat sebuah fungsi baru ketika menggunakannya di dalam elemen seperti button:

<button onClick={() => counter.increase(2)}>+</button>

Selain itu, kita dapat membuat operasi asynchronous pada fungsi action. Ini berguna ketika kita hendak mengambil atau mengirim data ke server.

Kita dapat menggunakan fungsi fetch sebagai contohnya, seperti ini:

action: async () => {
const response = await fetch('https://some-api.tld/endpoint');
set({ data: await response.json() });
},

useStore()

Pada kasus yang lebih nyata, biasanya kita memiliki beberapa jenis data yang berbeda di dalam store. Mungkin kita menaruh data user yang saat ini sedang login, atau menaruh data produk yang dimasukkan ke dalam keranjang oleh user.

Misal store-nya seperti ini:

function store(set, get) {
return {
user: { name: 'Nauval' },
cart: [],
addToCart: (product) => set({ cart: [product] }),
};
}

export const useStore = create(store);

Kita akan menaruh data user pada state user dan cart untuk menaruh data produk yang dimasukkan ke dalam keranjang, itu kenapa kita menggunakan array.

Sebagai contoh untuk data state cart, kitta dapat menggunakan store tersebut seperti ini:

const state = useStore((state) => ({
cart: state.cart,
addToCart: state.addToCart,
}));

Jika kita menggunakan action addToCart untuk menambah produk ke dalam keranjang, ia akan menambahkannya sesuai ekpektasi. Tapi, ketika kita menambahkan untuk kedua kalinya, maka data cart tetap ada satu produk, padahal seharusnya terdapat dua, karena kita sudah menambahkannya sebelumnya.

Ini karena kita perlu melakukan merge secara manual, karena Zustand tidak akan melakukan merge secara mendalam pada data masing-masing state. Jadi, kita perlu mengubah action addToCart menjadi seperti ini:

addToCart: (product) => set({ cart: [...get().cart, product] }),

Pada kasus yang lebih nyata, mungkin kamu perlu memeriksa produk yang sebelumnya sudah ditambahkan agar tidak ada duplikasi data di dalam keranjang. Misal produk dengan ID 1 sudah ditambahkan sebelumnya, kemudian terdapat produk dengan ID 1 ditambahkan kembali, seharusnya tidak menjadi dua datanya, melainkan nilai kuantitasnya yang menjadi 2 .

Sampai sini tidak ada masalah seharusnya, berikutnya kita akan coba mengatur rendering sebuah komponen yang mengkonsumsi data dari store yang sama.

Anggaplah kita memiliki komponen Cart.jsx yang di dalamnya menampilkan data cart , seperti ini:

import { useStore } from './stores/store';

export default function Cart() {
const state = useStore();

return (
<div>
{state.cart.map((item) => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
}

Kita juga butuh komponen untuk membuat daftar produk yang masing-masing memiliki tombol untuk menambahkannya ke dalam keranjang, seperti ini:

import { useStore } from './stores/store';

const products = [
{ id: 1, name: 'Product 1' },
{ id: 2, name: 'Product 2' },
];

export default function ProductList() {
const state = useStore((state) => ({
addToCart: state.addToCart,
}));

return (
<div>
{products.map((product) => (
<div key={product.id}>
<h2>{product.name}</h2>
<button onClick={() => state.addToCart(product)}>Add To Cart</button>
</div>
))}
</div>
);
}

Anggap saja nama komponennya ProductList.jsx.

Kita juga perlu membuat komponen Navbar.jsx untuk menampilkan data user , seperti ini:

import { useStore } from './stores/store';

export default function Navbar() {
const state = useStore((state) => ({ user: state.user }));

return <nav>User: {state.user.name}</nav>;
}

Terakhir, kita membutuhkan satu komponen untuk menampilkan semua komponen sebelumnya, anggap saja nama komponennya adalah App.jsx, seperti ini:

import Cart from './Cart';
import ProductList from './ProductList';
import Navbar from './Navbar';

function App() {
return (
<div>
<Navbar />
<hr />
<ProductList />
<hr />
<Cart />
</div>
);
}

export default App;

Sekarang, kita berikan console.log('render'); pada komponen Navbar.jsx yang sebelumnya kita sudah buat untuk mengetahui berapa kali komponen tersebut di-render.

Jadinya seperti ini:

import { useStore } from './stores/store';

export default function Navbar() {
const state = useStore((state) => ({ user: state.user }));

console.log('render');

return <nav>User: {state.user.name}</nav>;
}

Ketika membuka DevTools, seharusnya terdapat log bertuliskan render satu kali. Hal ini menandakan bahwa komponen tersebut sudah di-render sebanyak sekali.

Sekarang kita akan menekan tombol Add To Cart untuk menambahkan produk ke state cart , maka tulisan render di dalam console DevTools bertambah sesuai dengan berapa kali kita menekan tombol tersebut.

Ini artinya komponen Navbar melakukan render ulang secara tidak perlu, tidak efisien. Jika kita perhatikan, ketika tombol Add To Cart diklik, maka ia akan menambahkan data produk ke dalam state cart. Komponen yang mengakses data state tersebut adalah komponen Cart.jsx, bukan Navbar.jsx.

Tentu saja ini tidak efisien, seharusnya komponen Navbar tidak melakukan render ulang, karena ia hanya mengkonsumsi data state user . Untuk mengatasi hal ini, kita perlu menyisipkan fungsi shallow pada argumen kedua useStore , seperti ini:

import { useStore } from './stores/store';
import shallow from 'zustand/shallow';

export default function Navbar() {
const state = useStore((state) => ({ user: state.user }), shallow);

console.log('render');

return <nav>User: {state.user.name}</nav>;
}

Sekarang, jika kita klik tombol Add To Cart, komponen Navbar tidak akan melakukan render ulang.

Fungsi shallow akan membandingkan antara state saat ini di dalam store dengan state yang baru apakah setara atau tidak. Hal ini diperlukan untuk menentukan jika terdapat perubahan pada state store.

Sebagai contoh pada state cart , secara bawaan state tersebut memiliki nilai [] . Nilai tersebut merupakan nilai state saat ini untuk state cart . Jika kita menambah produk ke dalam keranjang, ini akan membuat state baru, misal [{ id: 1, name: 'Product 1' }] . Kedua state tersebut akan dibandingkan, apakah terdapat perubahan atau tidak. Jika terdapat perubahan, maka akan memicu render ulang terhadap komponen yang mengkonsumsi state tersebut.

Sederhananya, fungsi shallow dapat mencegah sebuah komponen melakukan render ulang ketika terdapat perubahan data yang tidak ia konsumsi.

Bukan hanya pada komponen Navbar, kita dapat menggunakannya pada komponen-komponen lain, pada kasus ini kita dapat menggunakannya di komponen ProductList.

import shallow from 'zustand/shallow';
import { useStore } from './stores/store';

const products = [
{ id: 1, name: 'Product 1' },
{ id: 2, name: 'Product 2' },
];

export default function ProductList() {
const state = useStore(
(state) => ({
addToCart: state.addToCart,
}),
shallow
);

console.log('render');

return (
<div>
{products.map((product) => (
<div key={product.id}>
<h2>{product.name}</h2>
<button onClick={() => state.addToCart(product)}>Add To Cart</button>
</div>
))}
</div>
);
}

Selain itu, kita juga dapat menggunakan destructuring untuk mengakses potongan state di dalam sebuah store. Misal seperti ini:

const { cart, addToCart } = useStore(
(state) => ({
cart: state.cart,
addToCart: state.addToCart,
}),
shallow
);

Tidak melulu harus object, kita dapat menggunakan array:

const [cart, addToCart] = useStore(
(state) => [state.cart, state.addToCart],
shallow
);

Pada kasus yang nyata, mungkin kita membuat beberapa store untuk setiap jenis data ketimbang menaruhnya di dalam satu store yang sama.

Middleware

Di Zustand, middleware adalah cara untuk menangkap sebuah tindakan yang dikirim ke store, sebelum proses tersebut diteruskan lebih lanjut. Middleware berupa sebuah fungsi JavaScript reguler.

Middleware dapat bermanfaat untuk beberapa tujuan, misal setiap kali kita melakukan perubahan di dalam store, kita ingin melakukan log ke browser DevTools. Contoh lain, kita ingin menyimpan perubahan pada store ke dalam local storage setiap state berubah.

Zustand memiliki beberapa middleware bawaan seperti immer, persist, redux, devtools, dan subscribeWithSelector. Setiap middleware memiliki fungsinya masing-masing.

Sebagai contoh, kita dapat menggunakan middleware persist untuk menyimpan state store kita ke dalam local storage, seperti ini:

import create from 'zustand';
import { persist } from 'zustand/middleware';

function store(set, get) {
return {
user: {
name: 'Nauval',
},
cart: [],
addToCart: (product) => set({ cart: [...get().cart, product] }),
};
}

export const useStore = create(
persist(store, {
name: 'my-store',
})
);

Dengan seperti ini, state akan disimpan ke dalam local storage dan ketika kita memuat ulang halaman tersebut di browser, maka state store akan menggunakan data yang ada di local storage sebagai data bawaan.

Argumen pertama pada middleware merupakan store yang kita ingin buat, sedangkan argumen kedua disuplai dengan opsi untuk middleware tersebut, dalam hal ini merupakan key untuk local storage.

Local storage browser

Selain persist, kita dapat menggunakan middleware devtools. Middleware ini memungkinkan kita menggunakan DevTools Redux untuk meng-inspect state store Zustand saat ini.

import create from 'zustand';
import { devtools } from 'zustand/middleware';

function store(set, get) {
return {
user: {
name: 'Nauval',
},
cart: [],
addToCart: (product) => set({ cart: [...get().cart, product] }),
};
}

export const useStore = create(devtools(store));

Kita dapat membuka DevTools Redux untuk meng-inspect state di dalam store saat ini.

DevTools Redux

Kita dapat menggabungkan kedua middleware, jadinya seperti ini:

import create from 'zustand';
import { devtools, persist } from 'zustand/middleware';

function store(set, get) {
return {
user: {
name: 'Nauval',
},
cart: [],
addToCart: (product) => set({ cart: [...get().cart, product] }),
};
}

export const useStore = create(
devtools(
persist(store, {
name: 'my-store',
})
)
);

Redux-like

Terakhir, jika kamu datang dari Redux, kamu dapat menggunakan konvensi Redux seperti reducer dan action types. Kita dapat menulis ulang store yang sebelumnya kita buat menjadi seperti ini dengan bantuan middleware redux:

import create from 'zustand';
import { redux } from 'zustand/middleware';

const initialState = {
user: {
name: 'Nauval',
},
cart: [],
};

function reducer(state, action) {
switch (action.type) {
case 'ADDTOCART':
return { cart: [...state.cart, action.payload] };
default:
throw new Error('Action is not recognized');
}
}

export const useStore = create(redux(reducer, initialState));

Untuk mengkonsumsi store tersebut kita dapat menggunakan cara yang sama seperti sebelumnya, hanya saja sekarang kita memiliki sebuah dispatcher untuk memperbarui state:

const [cart, dispatch] = useStore(
(state) => [state.cart, state.dispatch],
shallow
);

Sebenarnya kamu dapat membuat konstan yang berisi action types, seperti ini:

const types = { addtocart: 'ADDTOCART' }

Hanya saja saya menyederhanakan kode sebelumnya.

Penutup

Saya menggunakan Zustand pada beberapa proyek saya, termasuk proyek Next JS. Itu merupakan pengalaman yang begitu baik. Saya juga berharap ini akan menjawab permasalahanmu soal mengelola state di React, atau mungkin juga tidak~

Pada dasarnya kembali pada kebutuhanmu, mungkin kamu memang memerlukan Redux untuk pengelolaan state yang lebih kompleks. Lagipula, sejak adanya Redux Toolkit, penulisan Redux semakin ringkas dibanding versi yang lebih purba.

Kita bahas nanti, ya!

Kamu dapat mengikuti saya dan Kredibel di Medium untuk mendapatkan tulisan-tulisan ciamik lainnya. Sampai jumpa lagi!

--

--