Vì trên server, module được chia sẻ giữa các request. Một store tạo bằng create() ở cấp module là singleton của cả tiến trình server: dữ liệu user A ghi vào store có thể bị user B đọc thấy ở request sau. Ngoài rò rỉ dữ liệu, state còn dính giữa các lần render.
Cách đúng là store factory + Provider, mỗi request/mỗi cây React một instance:
// store factory — không gọi create() ở cấp module
export const createCounterStore = (init: CounterState) =>
createStore<CounterStore>()((set) => ({ ...init, inc: () => set(s => ({ n: s.n + 1 })) }))
// provider (client component)
export function CounterProvider({ children, init }: Props) {
const ref = useRef<CounterApi | null>(null)
if (!ref.current) ref.current = createCounterStore(init) // tạo đúng một lần
return <Ctx.Provider value={ref.current}>{children}</Ctx.Provider>
}
// consumer
export const useCounter = <T,>(sel: (s: CounterStore) => T) =>
useStore(useContext(Ctx)!, sel)Mấy điểm cần nói kèm khi trả lời:
- Dùng createStore (vanilla) + useStore, không dùng create — bản hook chỉ hợp cho store toàn cục phía client.
- Khởi tạo trong useRef (hoặc useState với initializer) chứ không phải trong thân component, tránh tạo lại store mỗi lần render.
- Store đã persist thì cần cờ hydrate, vì server không đọc được localStorage.
- Cách này còn giúp test và Storybook: mỗi test mount một Provider với state khởi tạo riêng, không cần reset singleton.