Simple Zustand

December 12, 2024 (2y ago)

0 views

Rewrite Zustand to be more simple and easier to use.

Codesanbox

zustand.js

// Phiên bản đơn giản của Zustand
import React from "react";
// Hàm tạo store với các tính năng cốt lõi
function createStore(createState) {
  // Lưu trữ state hiện tại
  let state;

  // Danh sách các hàm nghe (listener) để cập nhật khi state thay đổi
  const listeners = new Set();

  // Hàm để đăng ký các listener
  const subscribe = (listener) => {
    listeners.add(listener);

    // Trả về hàm hủy đăng ký
    return () => listeners.delete(listener);
  };

  // Hàm để cập nhật state
  const setState = (partial) => {
    // Tính toán state mới
    const nextState = typeof partial === "function" ? partial(state) : partial;

    // Kiểm tra nếu state thực sự thay đổi
    if (nextState !== state) {
      state = { ...state, ...nextState };

      // Thông báo cho tất cả các listener
      listeners.forEach((listener) => listener(state));
    }
  };

  // Hàm để lấy state hiện tại
  const getState = () => state;

  // Khởi tạo state ban đầu
  state = createState(setState, getState);

  // Trả về các phương thức để làm việc với store
  return {
    getState,
    setState,
    subscribe,
  };
}

// Hàm tạo hook để sử dụng trong React
function createHook(store) {
  return function useStore(selector) {
    // React hook để quản lý state
    const [state, setState] = React.useState(
      selector ? selector(store.getState()) : store.getState()
    );

    // Effect để đăng ký và hủy đăng ký listener
    React.useEffect(() => {
      const handleChange = (newState) => {
        const selectedState = selector ? selector(newState) : newState;

        // Chỉ cập nhật nếu state thay đổi
        setState(selectedState);
      };

      // Đăng ký listener
      const unsubscribe = store.subscribe(handleChange);

      // Hủy đăng ký khi component unmount
      return unsubscribe;
    }, [selector]);

    return state;
  };
}

// Hàm chính để tạo store dễ dàng
function create(createState) {
  // Tạo store
  const store = createStore(createState);

  // Tạo hook để sử dụng store
  const useStore = createHook(store);

  // Trả về hook và một số phương thức bổ sung
  return Object.assign(useStore, {
    getState: store.getState,
    setState: store.setState,
    subscribe: store.subscribe,
  });
}

export { create, createHook, createStore };

// Giải thích nguyên lý hoạt động:
// 1. createStore: Tạo cơ chế quản lý state cơ bản
//    - Lưu trữ state
//    - Cho phép đăng ký các listener
//    - Cung cấp phương thức cập nhật state
// 2. createHook: Tạo hook React để sử dụng store
//    - Quản lý state local
//    - Đăng ký listener để theo dõi thay đổi
//    - Chỉ render lại khi state thay đổi
// 3. create: Hàm chính để tạo store dễ dàng
//    - Kết hợp createStore và createHook
//    - Cung cấp API đơn giản để tạo và sử dụng store

// Các nguyên tắc chính:
// - Immutability: Luôn tạo state mới thay vì mutate
// - Minimal API: Chỉ cung cấp các phương thức cần thiết
// - Hiệu năng: Chỉ render khi state thực sự thay đổi

// Ý tưởng chính của thư viện:
// Zustand giải quyết các vấn đề quản lý state trong React bằng cách:
// - Tạo một store trung tâm để lưu trữ state
// - Cung cấp cơ chế đăng ký và theo dõi thay đổi
// - Cho phép cập nhật state một cách dễ dàng và hiệu quả
// - Giảm thiểu việc truyền props qua nhiều tầng component

App.js

import React from "react";
import { create } from "./zustand";

// Sử dụng hàm create đã định nghĩa từ đoạn code trước
// Tạo store quản lý trạng thái người dùng
const useUserStore = create((set) => ({
  // Trạng thái ban đầu
  user: null,
  isLoggedIn: false,
  theme: "light",

  // Các action để thay đổi state
  login: (userData) =>
    set({
      user: userData,
      isLoggedIn: true,
    }),

  logout: () =>
    set({
      user: null,
      isLoggedIn: false,
    }),

  toggleTheme: () =>
    set((state) => ({
      theme: state.theme === "light" ? "dark" : "light",
    })),
}));

// Component Profile sử dụng store
const Profile = () => {
  // Truy xuất state và actions từ store
  const { user, isLoggedIn, login, logout } = useUserStore();

  return (
    <div className={`p-6 ${isLoggedIn ? "bg-green-100" : "bg-red-100"}`}>
      {isLoggedIn ? (
        <div>
          <h2 className="text-2xl">Xin chào, {user.name}</h2>
          <p>Email: {user.email}</p>
          <button onClick={()=> logout()} className="mt-4 bg-red-500 text-white p-2 rounded">
            Đăng xuất
          </button>
        </div>
      ) : (
        <button
          onClick={()=>
            login({
              name: "Nguyễn Văn A",
              email: "[email protected]",
            })
          }
          className="bg-blue-500 text-white p-2 rounded"
        >
          Đăng nhập
        </button>
      )}
    </div>
  );
};

// Component chính
const UserManagementApp = () => {
  return (
    <div className="max-w-md mx-auto mt-10 space-y-4">
      <h1 className="text-3xl font-bold text-center">Quản Lý Người Dùng</h1>
      <Profile />
      <StateLogger /> {/* Component để hiển thị toàn bộ state */}
    </div>
  );
};

// Component để in ra toàn bộ state (để minh họa)
const StateLogger = () => {
  // Lấy toàn bộ state
  const state = useUserStore();

  return (
    <div className="bg-gray-100 p-4 rounded">
      <h3 className="font-bold mb-2">Trạng Thái Hiện Tại:</h3>
      <pre>{JSON.stringify(state, null, 2)}</pre>
    </div>
  );
};

export default UserManagementApp;

// Giải thích chi tiết về ví dụ:
// 1. Tạo store với nhiều trạng thái và actions
// 2. Sử dụng selector để lấy một phần state
// 3. Các component khác nhau có thể truy cập và thay đổi state
// 4. Không cần truyền props hay sử dụng Context
// 5. Dễ dàng mở rộng và quản lý state toàn cục
Simple Zustand | Cee