zustand 是一个状态管理库。官网
安装:npm install zustand
、yarn add zustand
基础使用:
1、首先创建一个store
create( ) 有三个参数:函数、布尔值、XX
可以放任何东西:基本类型值、对象、函数。
import create from 'zustand'
const useStore = create(set => ({
bears: 0,
name: 'zustand',
age: 18,
increasePopulation: () => set(state => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 })
}), false)
export default useStore
- 若第二个参数不传或为
false
时,新状态将会和create方法原来的返回值进行融合
;(默认为false) - 若第二个值为
true
时,新状态将会直接覆盖
create方法原来的返回值。 - 可以利用这个特性清空 store。
上面的例子是全局唯一的store,也可以通过 createContext
方式创建多实例 store,结合 Provider 使用。
2、使用方法
(1)获取所有状态。
// 这样会导致该组件在每一个状态变化时都要进行更新。
const state = useStore();
(2)选择多个状态切片。
// 获取方法与基本数据同理
const increasePopulation = useStore(state => state.increasePopulation)
const removeAllBears = useStore(state => state.removeAllBears)
(3)传递 shallow
构造一个内部要多个状态的对象。
import shallow from "zustand/shallow";
// 对象选取,当state.nuts或state.honey改变时,重新渲染组件。
const { name, age } = useStore(state => { name: state.name, age: state.age }, shallow)
// 数组选取,当state.nuts或state.honey改变时,重新渲染组件。
const [name, age] = useStore(state => [state.name, state.age], shallow);
// 映射选取,当state.treats在顺序、数量或对象键上发生变化时,重新渲染组件
const treats = useStore((state) => Object.keys(state.treats), shallow);
(4)demo:通过 setState
可直接修改状态
import useStore from './index';
import shallow from 'zustand/shallow';
import { Button } from '@douyinfe/semi-ui'
export const test= () => {
// 1、获取所有状态,通过点.使用
const state = useStore()
// 2、选择多个切片状态
const bears = useStore(state => state.bears)
const increasePopulation = useStore(state => state.increasePopulation)
const removeAllBears = useStore(state => state.removeAllBears)
// 3、使用 shallow 构造一个内部要多个状态的对象
// const { name, age } = useStore(state => { name: state.name, age: state.age }, shallow)// 对象选取
const [name, age] = useStore(state => [state.name, state.age], shallow);// 数组选取
// 通过 setState 直接修改状态
const subtractBears = () => {
useStore.setState({ bears: bears - 1, age: age - 1})
}
return (<div>
<h1>bears:{bears}</h1>
<h1>bears:{state.bears}</h1>
<h1>name:{name}</h1>
<h1>age:{age}</h1>
<Button onClick={increasePopulation}>加1</Button>
<Button onClick={subtractBears}>减1</Button>
<Button onClick={removeAllBears}>重置为0</Button>
</div>)
};
记忆化选择器
通常建议用 useCallback 来记忆选择器。这将避免在每次渲染时进行不必要的计算。
利用 useCallback 甚至可以跳过普通 compare,而仅关心外部 id 值的变化。
const fruit = useStore(useCallback((state) => state.fruits[id], [id]));
原理是id变化时,useCallback
返回值才会变化,而 useCallback
返回值如果不变,useStore 的compare函数引用对比就会为true。
异步 action
mock 实例
// 1、创建store
const useStore = create((set: any, get: any) => ({
// 定义普通变量,可用来保存异步的结果
headerData: [],
inProcessData: [],
recentActivityData: [],
// 定义异步请求函数
getWorkBeachData: async () => {
const res = await request({ url: '/workbeach', method: 'get' })
const { headerData, inProcessData, recentActivityData } = res.data
// 将请求到的数据直接 set存入
set({
headerData,
inProcessData,
recentActivityData
})
}
}))
2、获取与使用状态
import React, { useEffect } from 'react'
import useStore from '../../../store/blank';
import shallow from 'zustand/shallow';
const Index: React.FC = () => {
// 获取状态
const [headerData, inProcessData, recentActivityData] = useStore(state => [state.headerData, state.inProcessData, state.headerData], shallow);// 数组选取
const getWorkBeachData = useStore((state) => state.getWorkBeachData);
// 渲染组件时执行定义好的方法,即会更新状态
useEffect(() => {
getWorkBeachData();
}, []);
// 按需使用变量数据即可
return <div>...</div>
}
export default Index
通过 set
从 action 中读取状态
访问它之外的状态。
const useStore = create((set, get) => ({
name: "zustand",
action: () => {
const name = get().name // 读取上面定义好的变量
console.log(name) // zustand
// ...
}
})
读取/写入状态并对组件外的变化做出响应
有时你需要以非响应式的方式访问状态,或者对 store 进行操作。对于这些情况,返回的 hook 在其原型上附加了一些实用函数。(未完全理解)
const useStore = create(() => ({ paw: true, snout: true, fur: true }))
// 获得最新的且非响应式的状态
const paw = useStore.getState().paw
// 监听所有的变化,每次变化是将同步触发
const unsub1 = useStore.subscribe(console.log)
// 更新状态,将触发监听器
useStore.setState({ paw: false })
// 取消订阅
unsub1()
// 销毁store(删除所有订阅)。
useStore.destroy()
// 当然,你可以像往常一样使用hook
function Component() {
const paw = useStore(state => state.paw)
}
在没有 React 的情况下使用 zustand
zustands 的核心可以在不依赖 React 的情况下被导入和使用。
唯一的区别是,创建函数不返回 hook,而是返回一系列 api 函数。
import create from 'zustand/vanilla'
const store = create(() => ({ ... }))
const { getState, setState, subscribe, destroy } = store
甚至可以用 React 消费现有的 vanilla store。
import create from "zustand";
import vanillaStore from "./vanillaStore";
const useStore = create(vanillaStore);
注意修改set或get的中间件不应用于getState和setState。