create 方法可以帮助我们创建一个自定义 hook 用于状态管理
1import { create } from 'zustand'23const useSomeStore = create(stateCreatorFn)
1type Create = {2<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>): UseBoundStore<Mutate<StoreApi<T>, Mos>>;3<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>) => UseBoundStore<Mutate<StoreApi<T>, Mos>>;4};
create 接收一个名为 stateCreatorFn 的函数作为参数. 该函数的也接收三个参数, 绝大多数情况下, 我们只需要使用第一个参数即可
1// 通常只使用第一个参数2stateCreatorFn(setState, getState, store) {}
1export const useStore = create((set) => ({2x: 0,3y: 0,4update: (event: MouseEvent) => set({5x: event.pageX,6y: event.pageY7}),8}))
create 函数运行之后返回一个 react hooks, 我们可以利用返回的 hook 访问 getState 、setState 、getInitialState 、subscribe 四个方法.
例如, 上一章的案例, 我们可以利用 setState 进行改写来单独创建更新函数, 注意观察 store.ts
01import { create } from 'zustand'0203type Store = {04x: number,05y: number06}0708export const useStore = create<Store>((set) => ({09x: 0,10y: 011}))1213export function update(e: MouseEvent) {14useStore.setState(state => ({15x: e.pageX,16y: e.pageY17}))18}19
在组件中, 我们可以直接通过解构的方式获取状态
1const { x, y } = useStore()
这种方式的好处就是写起来比较简洁优雅. 但是在 zustand 中, 他会存在很大的性能风险, 因为 store 中其他状态的更新, 当前组件也会受到影响从而导致冗余的 re-render. 如果你确保 store 的状态不会在别的组件中更新, 那么就可以这样使用.
另外一种方式就是使用 selector 对状态进行选取, 它可以有效的避免冗余的 re-render, 坏处就是看上去不够优雅. 许多开发者也因为这个原因而选择放弃 zustand, 这个主要看个人喜好
1const x = useStore(state => state.x)2const y = useStore(state => state.y)
完整的案例如下
01import { useEffect } from 'react'02import { useStore, update } from './store'0304export default function Counter() {05const x = useStore(state => state.x)06const y = useStore(state => state.y)0708useEffect(() => {09window.addEventListener('mousemove', update)10return () => {11window.removeEventListener('mousemove', update)12}13}, [])1415return (16<div className='text-center p-4'>17鼠标当前位置18<div className='font-bold text-2xl mt-4'>{x}, {y}</div>19</div>20)21}
我们还可以使用 useShallow 来在可以解构的情况下,避免不必要的 re-render,但是这种写法不一定更优化,看个人喜好
1import { useShallow } from 'zustand/react/shallow'23const { x, y } = useStore(useShallow(state => ({4x: state.x,5y: state.y6}))