前言:

        在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 和 persistZustand常用的中间件

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 }),
    }),
  ),
)

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐