创建 store
import { create } from 'zustand'
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}))在 React 组件中使用 store:
function Counter() {
// 不推荐,任一状态发生变化都会触发重渲染
const store = useStore()
const {count, increment, decrement, reset} = useStore()
// 推荐, 选择器只订阅关注的状态
const count = useStore((state) => state.count)
// 选择器也支持函数
const increment = useStore((state) => state.increment)
const decrement = useStore((state) => state.decrement)
const reset = useStore((state) => state.reset)
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
)
}在 React 组件外如工具类中使用 store:
useStore.getState().increment()
useStore.subscribe((state) => console.log(state))使用浅比较,避免引用变化导致多余渲染
import { create } from 'zustand'
import { useShallow } from 'zustand/react/shallow'
const useMeals = create(() => ({
papaBear: 'large porridge-pot',
mamaBear: 'middle-size porridge pot',
littleBear: 'A little, small, wee pot',
}))
export const BearNames = () => {
const names = useMeals(useShallow((state) => Object.keys(state)))
return <div>{names.join(', ')}</div>
}选择器也可以同时指定多个属性:
import { create } from 'zustand'
import { useShallow } from 'zustand/react/shallow'
// Bear store with explicit types
interface BearState {
bears: number
food: number
}
const useBearStore = create<BearState>()(() => ({
bears: 2,
food: 10,
}))
// In components, you can use both stores safely
function MultipleSelectors() {
// 指定多个属性
const { bears, food } = useBearStore(
useShallow((state) => ({ bears: state.bears, food: state.food })),
)
return (
<div>
We have {food} units of food for {bears} bears
</div>
)
}有些状态不需要单独有个字段存储,可以使用现有状态计算出来:
import { create } from 'zustand'
interface BearState {
bears: number
foodPerBear: number
}
const useBearStore = create<BearState>()(() => ({
bears: 3,
foodPerBear: 2,
}))
function TotalFood() {
// 计算状态,无需有个属性存储
const totalFood = useBearStore((s) => s.bears * s.foodPerBear)
return <div>We need ${totalFood} jars of honey</div>
}状态也可以支持异步:
interface UserState {
user: User | null;
loading: boolean;
fetchUser: (id: string) => Promise<void>;
}
const useUserStore = create<UserState>((set) => ({
user: null,
loading: false,
fetchUser: async (id) => {
set({ loading: true });
try {
const user = await api.getUser(id);
set({ user, loading: false });
} catch (error) {
set({ loading: false });
throw error;
}
},
}));在 state 中既有属性又有方法时,代码会混在一起:
import { create } from 'zustand'
interface StoreState {
count: number
}
interfact StoreAction {
increment: (state) => void;
decrement: (state) => void;
reset: (state) => void;
}
const useStore = create<StoreState&StoreAction>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}))
// State + actions are separated
export const useBearStore = create<StoreState & StoreAction>()(
combine(
{ bears: 0 },
(set) => ({
increase: () => set((s) => ({ bears: s.bears + 1 })),
})),
)如果不想页面刷新一下数据就没了,比如登陆信息,需要把数据持久化。
默认是持久化到 localStorage,可以调整到 sessionStorage,可以自己实现如把一些页面查询参数持久化到 url 中:Connect State with URL Hash
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
interface BearState {
bears: number
increase: () => void
}
export const useBearStore = create<BearState>()(
persist(
(set) => ({
bears: 0,
increase: () => set((s) => ({ bears: s.bears + 1 })),
}),
{ name: 'bear-storage' }, // localStorage key
),
)对于嵌套对象:
type State = {
deep: {
nested: {
obj: { count: number }
}
}
}更新属性的时候,需要展开所有层级:
normalInc: () =>
set((state) => ({
deep: {
...state.deep,
nested: {
...state.deep.nested,
obj: {
...state.deep.nested.obj,
count: state.deep.nested.obj.count + 1
}
}
}
})),可以使用 immer 更新嵌套对象:
import { immer } from 'zustand/middleware/immer';
const useStore = create(
immer((set) => ({
user: { name: 'John', age: 30 },
updateAge: (newAge) =>
set((state) => {
state.user.age = newAge; // 直接修改,Immer会处理不可变性
}),
}))
);对于非嵌套对象,set 会自动 merge 状态,不需要手动展开
import { create } from 'zustand'
const useCountStore = create((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
// inc: () => set((state) => ({ ...state, count: state.count + 1 })) 不需要手动展开 ...state
}))如果想要禁用 set 的自动 merge,添加一个 replace 参数即可:
set((state) => newState, true)如果想观察 zustand 状态变更,可以使用 devtools:
import { devtools } from 'zustand/middleware'
const useStore = create(
devtools((set) => ({ /* ... */ }))
)