跳到主要内容

zustand 教程

基础

安装
npm install zustand
定义全局状态变量
import { create } from "zustand";
const useBearStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}));
使用全局状态变量
import useBearStore from "use_bear_store";
const BearCounter = () => {
const bears = useBearStore((state) => state.bears);
return <h1>{bears} around here ...</h1>;
};
内部行为访问状态
// 使用 get 参数
const useSoundStore = create((set, get) => ({
sound: "grunt",
action: () => {
const sound = get().sound
// ...
}
})
渲染机制
  • zustand 中 state 发生改变;
  • zustand 会从新渲染所有使用该 state 的组件;

工具链

ts

import { create } from "zustand";
// 定义接口
interface BearStore {
bears: number;
increasePopulation: () => void;
removeAllBears: () => void;
}
// 通过泛型使用接口
const useBearStore = create<BearStore>((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}));

immer

中间件

持久化存储

import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";

export const useBearStore = create(
persist(
(set, get) => ({
bears: 0,
addABear: () => set({ bears: get().bears + 1 }),
}),
{
// name 必须指定且唯一
name: "food-storage",
// 默认为 localStorage
// 可选 sessionStorage, AsyncStorage, IndexedDB
storage: createJSONStorage(() => sessionStorage),
}
)
);

最佳实践

组件只有 action 而没有 state

  • zustand 根据 state 的变化决定是否渲染组件;
  • 若组件只有 action 而没有 state;
  • state 发生改变,该组件不会重新渲染;
// 该组件不会重新渲染
const App = () => {
// const modelStatus = useModelsStatus((state) => state.modelStatus);
const addModelStatus = useModelsStatus((state) => state.addModelStatus);
// ...
return <></>;
};

zustand 的闭包问题

  • 由于 react 闭包,zustand 无法获取最新的值;
  • 使用 zustand 中的 get() 函数可以获取最新的值;
// store.tsx
import { create } from "zustand";

interface Store {
count: number;
setCount: (value: number) => void;
getCount: () => number;
}

export const useStore = create<Store>((set, get) => ({
count: 0,
setCount: (value: number) => {
set({
count: value,
});
},
getCount: () => get().count,
}));

// App.tsx
const App = () => {
const count = useStore((state) => state.count);
const setCount = useStore((state) => state.setCount);
const getCount = useStore((state) => state.getCount);

useEffect(() => {
const id = setInterval(() => {
setCount(count + 1);
setCount(getCount() + 1);
}, 1000);
return () => clearInterval(id);
}, []);

return <h1>{count}</h1>;
};