一个简单的,快速的状态管理解决方案,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