一个简单的,快速的状态管理解决方案,api设计基于函数式和hooks
安装:
npm install zustand
基础使用
让我们实现一个非常简单的计数器案例完成我们的第一个store
1- 创建一个counterStore
create( ) 有三个参数:函数、布尔值、XX
可以放任何东西:基本类型值、对象、函数。
- 若第二个参数不传或为
false
时,新状态将会和create方法原来的返回值进行融合
;(默认为false) - 若第二个值为
true
时,新状态将会直接覆盖
create方法原来的返回值。 - 可以利用这个特性清空 store。
import create from 'zustand'const useCounterStore = create((set) => ({// 数据count: 0,// 修改数据的方法increase: () => set(state => ({ count: state.count + 1 })),decrease: () => set(state => ({ count: state.count - 1 }))
}))export default useCounterStore
2- 绑定到组件
import useCounterStore from './store'const App = () => {const count = useCounterStore((state) => state.count)const decrease = useCounterStore((state) => state.increase)const increase = useCounterStore((state) => state.decrease)return (<div><button onClick={decrease}>+</button><span>{count}</span><button onClick={increase}>-</button></div>)
}export default App
3- 使用方法
- 获取所有状态
// 这样会导致该组件在每一个状态变化时都要进行更新。
const state = useStore();
- 选择多个状态切片
// 获取方法与基本数据同理
const increasePopulation = useStore(state => state.increasePopulation)
const removeAllBears = useStore(state => state.removeAllBears)
- 传递
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);
- 通过
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]));
异步支持
1- 创建异步action
import create from 'zustand'const fetchApi = () => {return new Promise((resolve) => {setTimeout(() => {resolve(['vue', 'react'])}, 2000)})
}const useListStore = create((set) => ({// 数据list: [],// 修改数据的方法fetchList: async () => {const res = await fetchApi()set({ list: res })}
}))export default useListStore
2- 绑定组件
import { useEffect } from 'react'
import useListStore from './store'const App = () => {const list = useListStore((state) => state.list)const fetchList = useListStore((state) => state.fetchList)useEffect(() => {fetchList()}, [])return (<div>{JSON.stringify(list)}</div>)
}export default App
在没有 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。
增加调试
简单的调试我们可以安装一个 名称为 simple-zustand-devtools 的调试工具
1- 安装调试包
$ yarn add simple-zustand-devtools
2- 配置调试工具
import create from 'zustand'// 导入核心方法
import { mountStoreDevtool } from 'simple-zustand-devtools'const useStore = create((set) => ({}))// 开发环境开启调试
if (process.env.NODE_ENV === 'development') {// 第一个参数为调试的store标识mountStoreDevtool('counterStore', useStore)
}export default useStore