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。

未完待续…

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐