Khairul Hidayat

Frontend Developer

DIY Zustand dari nol? Gass

Frontend
State management favorit saya nih, gimana sih cara kerja / behind the scenenya? Yuk kita coba rancang sendiri
DIY Zustand dari nol? Gass

Belum reinvent-the-wheel, belum sah jadi js dev.

Siapa sih yang gak kenal Zustand, salah satu state management untuk React. Diantara zustand, mungkin banyak juga yang lebih prefer menggunakan alternatif lain seperti Redux, Jotai, Recoil, dsb. Alasan saya pribadi menggunakan Zustand sebagai state management utamanya karena simple, ringan, dan boilerplate-free.

Setelah sekian lama menggunakan zustand maupun state managament lainnya, saya penasaran dong, gimana sih ini library cara kerjanya? Apa aja yg ada di belakangnya? Kok bisa ngelempar state yang sama ke beberapa component tanpa harus react context?

Yaudah daripada gabut pas ada waktu luang, jadinya saya nyoba nih buat zustand saya sendiri dari nol. Yuk langsung aja kita praktik.

React Context

Sebelumnya saya pernah make Context & useState bawaan react untuk manage state di app saya biar bisa dipake gak hanya di parent component, tetapi di children2 sampe di cucu & cicitnya juga bisa pake.

Awalnya oke aja tuh, tapi setelah appnya lumayan gede, muncul nih satu problem. Performanya jelek. Bisa dilihat di contoh atas, ketika tombol + ataupun - dipencet, sub-komponennya juga pada rerender juga semua (cek console & tgl/waktu yg dibawah).

Alasannya? semua sub-komponen terjadi rerender karena useStatenya berapa di parent component. Untuk project kecil seperti di atas mungkin tidak terlalu terasa, lain halnya misal sudah gede codebasenya.

Jadi, gimana nih solvenya biar cegah children component yang tidak menggunakan state tersebut tidak ikut rerender juga?

Pake state management semacam Zustand, jotai, atau lainnya yang bisa subscribe/listen state change per component.

Observable Pattern

Ketika ngulik2 design pattern untuk react, gak sengaja ada nemu yg namanya Observable Pattern. Pattern ini juga jadi dasar dari RxJs.

Berikut contoh simple dari implementasi Observable.

Kayaknya cocok ya untuk ngerancang zustand from scratch?

Store

Pertama-tama, kita perlu membuat Store Creator. Store ini nantinya akan menyimpan data, subscribe terhadap perubahan, dan mengubah data tersebut.

Fungsi ini yang akan bertanggung jawab untuk membuat penampungan state beserta observablenya, kemudian mengembalikan hasil berupa fungsi untuk mengambil data, mengubah data, dan berlangganan terhadap perubahan data.

State Observer Hooks

Store yang sudah kita buat sebelumnya sudah bisa menyimpan & mengubah data, tetapi belum bisa digunakan sebagai state di react. Agar bisa digunakan di komponen react, kita perlu “membungkus” store tersebut dengan custom hooks.

useStore.ts

import { useEffect, useState } from "react";
import { Store } from "./createStore";

const useStore = <T>(store: Store<T>) => {
  // Buat state lokal untuk trigger rerender
  // ketika ada perubahan state
  const [state, setState] = useState<T>(store.getState());

  useEffect(() => {
    // Langganan terhadap perubahan state, dan ubah ketika
    // terdapat perbedaan dengan state sebelumnya
    const unsubscribe = store.subscribe((prev, next) => {
      if (prev !== next) {
        setState(next);
      }
    });

    // Hentikan berlangganan ketika cleanup
    return () => {
      unsubscribe();
    };
  }, []);

  return state;
};

export default useStore;

Penggunaan

Untuk menggunakan hooks di atas, kurang lebih sama seperti useStore yang ada di zustand.

// Buat counter store
const counter = createStore(() => 0);

// Actions (ya, saya penganut no store actions)
// https://docs.pmnd.rs/zustand/guides/practice-with-no-store-actions
const increase = () => counter.setState((count) => count + 1);
const decrease = () => counter.setState((count) => count - 1);

const App = () => {
  const count = useStore(counter);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={decrease}>-</button>
      <button onClick={increase}>+</button>
    </div>
  );
};

Setelah itu, mari kita coba gunakan “DIY Juztand” yang telah kita buat pada project React Context di atas dan mencoba memperbaiki issue rerender yang ada.

Jika kita lihat Console dan menekan tombol - ataupun +, komponent yang rerender hanya komponen Counter saja. Waktu/tgl yang ada di bawah juga sudah tidak mengalami perubahan.

Penutup

Dengan menggunakan state management & practice yang tepat, kita bisa meningkatkan performa react app kita agar lebih baik lagi. “DIY Juztand” yang telah dibuat di atas sangatlah simple, bahkan belum ada fitur selector yang ada di library aslinya. Banyak hal yang masih bisa diimpove untuk DIY state management kita ini.

Semua ini untuk pembelajaran saja. Daripada menghabiskan waktu membuat dari nol, lebih baik menggunakan apa yang sudah ada saja, lebih cepat.

Source code dari hasil project di atas bisa dilihat disini.

Referensi