react+Zustand来管理公共数据,类似vue的pinia
·
前言:
在react中,我们常用的状态管理工具就是redux,像他的官方提供的工具redux Toolkit 已经很简洁,好用了,除了这个之外的话,还有出现的Zustand也能简洁高效的管理我们的公共数据,相比较redux的官方工具更简洁,类似我们vue3出来的pinia的工具,定位是一样的,这里来说一说他。
Zustand 与 Redux(及 Redux Toolkit)对比
| 维度 | Zustand | Redux |
|---|---|---|
| 定位 | 轻量级状态管理(单 store) | 企业级状态管理(支持复杂场景) |
| 学习曲线 | 极简 API,上手快 | 概念较多(action/reducer/middleware) |
| 不可变性 | 默认可变(类似 Vuex) | 严格不可变(需返回新状态) |
| 模板代码 | 几乎为零 | Redux 较多,Redux Toolkit 减少 |
| 特性 | Zustand | Redux |
|---|---|---|
| Store 数量 | 多个独立 store | 单一 store,模块化通过 slices |
| 更新机制 | 直接调用 set 方法 | 必须 dispatch(action) |
| 性能优化 | 自动选择组件所需状态 | 需手动优化(如 shallowEqual) |
| 中间件 | 支持(如持久化、日志) | 生态强大(redux-thunk/saga 等) |
| DevTools | 需手动集成 | 默认支持 |
| TypeScript 支持 | 极佳 | 优秀(Redux Toolkit 更完善) |
具体使用:
1、安装
npm i zustand
2、简洁使用
store/index.js
import create from 'zustand';
export const useCounterStore = create((set) => ({
//定义变量
count: 0,
//定义方法,直接修改变量内容
increment: () => set((state) => ({ count: state.count + 1 })),
reset: () => set({ count: 0 }),
}));
界面jsx中
import { useCounterStore } from '@/store'
//定义好的变量和事件,直接就能取到
const { count, increment } = useCounterStore();
//用的时候,直接{}就能拿到,跟普通变量一样,事件也是直接就能调用
return <button onClick={increment}>{count}</button>;
3、项目正常使用,使用中级件
immer和persist是 Zustand常用的中间件
immer直接修改状态(类似 Vue 或 MobX 的写法),而 不需要手动返回新状态。(你的状态结构较复杂(如嵌套对象、数组)时,避免手写
...spread或Object.assign)
persist:持久化到本地存储,刷新后丢失
immer 的具体使用方法
可以看到,immer方法里面也可以直接写变量和事件,同步异步都一样
入参是set和get,set修改变量,get获取变量内容和调用其它定义的方法
mport { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
// 使用 immer 中间件
const useTodoStore = create(
immer((set) => ({ //set可以简写不要括号
// 定义变量
todos: [],
// 定义方法
addTodo: (text) =>
set((state) => {
state.todos.push({ text, done: false });
}),
}))
);
persist 的具体使用方法
1、persist有两个参数,第一个是回调函数,入参两个,set可以修改定义的变量,get可以获取调用当前定义好的变量与事件,第二个是缓存的配置
2、定义变量和方法直接在里面写就行了,不用initialState、reducers这种定义方法
3、异步方法和同步方法的区别直接是可以用async来定义异步,await来掉接口,同步就是方法里写逻辑,其它没区别
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { loginApi } from '@/api/test'//封装的axios请求方法
// 使用 persist 中间件
const useAuthStore = create(
persist((set,get) => ({
// 定义的变量
user: null,
token:'',
// 定义的事件
login: (userData) => set({ user: userData }),//set方法直接修改变量内容,不用state
getToken: async () => {
get().login() //可以通过这种方式,调用其它方法
// 异步调用接口
const res = await loginApi(form)
set((state) => {
state.token = res.token
state.user = res
})
},
}),
{
name: 'auth-storage', // localStorage 的 key
getStorage: () => localStorage, // 默认是 localStorage
// 可选:只持久化部分字段
partialize: (state) => ({ user: state.user,token: state.token }),
}
)
);
4、源码分享
当 immer和 persist 同时使用,immer放外面,persist放里面,参数还是 set和get
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'
import { persist } from 'zustand/middleware'
import { useTabbarStore } from './tabbar'
import { useMenuStore } from './menu'
import { STORAGE_PREFIX, USER } from '@/config/cache'
import { loginApi, logoutApi } from '@/api/test'
interface IState {
token: string
userInfo: any
}
interface IActions {
init: () => void
login: (form: any) => Promise<void>
logout: () => Promise<void>
}
export const useUserStore = create<IState & IActions>()(
immer(
persist((set, get) => ({
token: '',
userInfo: {},
init: () => {
useMenuStore.getState().init()
useTabbarStore.getState().init()
set((state) => {
state.token = ''
state.userInfo = {}
})
},
login: async (form) => {
get().init()
const res = await loginApi(form)
set((state) => {
state.token = res.token
state.userInfo = res
})
},
logout: async () => {
await logoutApi().then(() => {
get().init()
})
},
}), {
name: `${STORAGE_PREFIX}${USER}`,
partialize: state => ({ token: state.token, userInfo: state.userInfo }),
}),
),
)
更多推荐



所有评论(0)