Mục lục

State Management: Zustand vs React Query

Chiến lược quản lý trạng thái cho hệ thống lớn. Khi nào dùng Global Store? Khi nào dùng Server State?

Trong mô hình Monorepo E-commerce này, chúng ta phân chia State thành 2 loại rõ rệt.

1. Server State (Async Data) -> React Query

Dữ liệu từ Server (Danh sách sản phẩm, Chi tiết đơn hàng) KHÔNG nên lưu trong Redux/Zustand. Chúng nên được quản lý bởi TanStack Query (hoặc SWR).

Lợi ích:

  • Tự động Caching & Deduping.
  • Tự động Re-fetch khi focus cửa sổ.
  • Xử lý Loading/Error states cực nhàn.
tsx:
// apps/merchant/hooks/use-orders.ts
import { useQuery } from "@tanstack/react-query";
import { getOrders } from "@/actions/order";

export function useOrders(page: number) {
  return useQuery({
    queryKey: ['orders', page],
    queryFn: () => getOrders(page),
    staleTime: 5 * 60 * 1000, // 5 phút chưa cần fetch lại
  });
}

2. Client State (UI State) -> Zustand

Dữ liệu thuần Client (Giỏ hàng, Sidebar Toggle, Modal Open/Close) được quản lý bởi Zustand.

Tại sao Zustand?

  • Nhẹ hơn Redux (dưới 1KB).
  • API đơn giản (Hooks base).
  • Không cần bọc Context Provider.
tsx:
// apps/store/store/cart.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface CartState {
  items: CartItem[];
  addItem: (product: Product) => void;
  removeItem: (id: string) => void;
}

export const useCartStore = create<CartState>()(
  persist(
    (set) => ({
      items: [],
      addItem: (product) => set((state) => {
        // Logic thêm vào giỏ...
      }),
      removeItem: (id) => set((state) => ({
        items: state.items.filter(i => i.id !== id)
      })),
    }),
    { name: 'shopping-cart' } // Tự động lưu vào LocalStorage
  )
);

3. URL State (The Truth)

Với Admin Dashboard (Filter, Search, Pagination), trạng thái PHẢI nằm trên URL.

  • User có thể copy link gửi cho sếp -> Sếp thấy đúng trạng thái đó.
  • Refresh trang không bị mất filter.

Bad:

tsx:
const [search, setSearch] = useState("");

Good:

tsx:
const searchParams = useSearchParams();
const search = searchParams.get("search");

const handleSearch = (term) => {
  router.push(`?search=${term}`);
}

Tổng kết

Loại StateCông nghệÁp dụng cho
Server StateReact QueryAPI Respsonse, DB Data
Client GlobalZustandCart, Theme, User Session (Client side)
URL StateNext.js RouterSearch, Sort, Pagination, filter
Form StateReact Hook FormForm validation, Input values
Quảng cáo
mdhorizontal