zustand是目前比较流行的用于替代redux库的状态管理方案,主要有以下几个优点 更少的样板代码,基于状态变更的渲染,基于hooks的使用方法,集中的状态管理等。
基本使用:
import { create } from 'zustand'
const useCountStore = create((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}))
这样就可以在组件中使用useCountStore了
import { shallow } from 'zustand/shallow'
import { useShallow } from 'zustand/react/shallow';
// shallow 避免不必要的重渲染
zustand v4版本写法
const [count, inc ] = useCountStore(state=>[count,inc], shallow)
or
const {count, inc} = useCountStore(state=>{count,inc}, shalow)
或者使用 zustand v5版本写法
const { count, inc } = useCountStore(useShallow(state => ({ count: state.count,inc:state.inc })) );
纯js操作环境下取值:
const state = useCountStore.getState()
state.值名称
解构成数组或者对象使用更方便。
actions操作除了可以定义在create方法中, 还可以定义在外部使用 eg:
export const useBoundStore = create(() => ({
count: 0,
text: 'hello',
}))
export const inc = () =>
useBoundStore.setState((state) => ({ count: state.count + 1 }))
export const setText = (text) => useBoundStore.setState({ text })
通过setState方法可以操作store里面的数据。
嵌套对象: 使用immer
首先需要安装immer
npm install immer
immer 通过producers操作原始数据,达到数据不可变的目的,对于深层数据的操作具有便捷性和易用性等特征。同时简化了不可变数据结构的处理。
嵌套数据结构eg:
import {produce} from "immer"
// 复杂数据结构例子
const store = {
users: new Map([
[
"17",
{
name: "Michel",
todos: [
{
title: "Get coffee",
done: false
}
]
}
]
])
}
// 深度更新
const nextStore = produce(store, draft => {
draft.users.get("17").todos[0].done = true
})
// 过滤
const nextStore = produce(store, draft => {
const user = draft.users.get("17")
user.todos = user.todos.filter(todo => todo.done)
})
nextStore是一份新的经过处理过的对象,与原始的对象不同。draft是 根据 store 生成的草稿状态,它是 store 的代理,对 draft 所做的任何修改都将被记录并用于生成 nextStore 。在此过程中,store (即原始状态)将不受影响。
切片模式:
定义两份或者多份数据存储,并最终合并成一份store使用。 多个store存在时十分有用。
样板代码:
import { create } from 'zustand'
export const createFishSlice = (set) => ({
fishes: 0,
addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
})
export const createBearSlice = (set) => ({
bears: 0,
addBear: () => set((state) => ({ bears: state.bears + 1 })),
eatFish: () => set((state) => ({ fishes: state.fishes - 1 })),
})
// 一个函数中更新多份store数据
export const createBearFishSlice = (set, get) => ({
addBearAndFish: () => {
get().addBear()
get().addFish()
},
})
export const useBoundStore = create((...a) => ({
...createBearSlice(...a),
...createFishSlice(...a),
...createBearFishSlice(...a), // 更新多份store数据操作。
}))
useShallow预防出现重渲染。取值时使用useShallow包裹取值状态
const state = useEGStore(useShallow((state) => Object.keys(state)))
//对象取值
const { nuts, honey } = useBearStore(
useShallow((state) => ({ nuts: state.nuts, honey: state.honey })),
)
//数组取值
const [nuts, honey] = useBearStore(
useShallow((state) => [state.nuts, state.honey]),
)
zustand的订阅和取消订阅
实际过程中会根据状态来进行具体的业务开发,订阅操作是十分强大的功能。适用于跨组件数据共享、数据监听操作。
import { subscribeWithSelector } from 'zustand/middleware'
需要使用subscribeWithSelector中间件包裹状态 否则不能细粒度的监听状态变化。
import { shallow } from 'zustand/shallow'
const useDogStore = create(
subscribeWithSelector(() => ({ paw: true, snout: true, fur: true })),
)
// paw改变时执行回调
const unsub2 = useDogStore.subscribe((state) => state.paw, console.log)
// 新旧值监听
const unsub3 = useDogStore.subscribe(
(state) => state.paw,
(paw, previousPaw) => console.log(paw, previousPaw),
)
// Subscribe also supports an optional equality function
// 可选 浅比较options
const unsub4 = useDogStore.subscribe(
(state) => [state.paw, state.fur],
console.log,
{
equalityFn: shallow, // 浅比较
fireImmediately: true, // 是否立即执行监听
},
)
// 返回取消监听函数 可在组件销毁时执行。
持久化操作
使用persist持久化中间件 将数据存储在Storge里
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'
const useFishStore = create(
persist(
(set, get) => ({
fishes: 0,
addAFish: () => set({ fishes: get().fishes + 1 }),
}),
{
name: 'food-storage', // name of the item in the storage (must be unique)
storage: createJSONStorage(() => sessionStorage), // 默认 sessionStorage 'localStorage' is used
},
),
)