后台系统从零搭建(二)—— 系统架构设计6之zustand状态管理

240 阅读4分钟

本系列从零搭建一个后台系统,技术选型React18 + ReactRouter7 + Vite4 + Antd5 + zustand + TS。 这个系列文章将会从零开始,一步一步搭建一个后台系统,这个系统将会包括登录、权限、菜单、用户、角色等功能。

已实现的项目地址,如果需要接口,还需要运行接口项目

后台系统从零搭建(一)—— 项目基础
后台系统从零搭建(二)—— 系统架构设计1之路由封装
后台系统从零搭建(二)—— 系统架构设计2之Axios请求封装
后台系统从零搭建(二)—— 系统架构设计3之环境变量封装
后台系统从零搭建(二)—— 系统架构设计4之CSSModule、主题、登录页
后台系统从零搭建(二)—— 系统架构设计5之公共布局Layout
后台系统从零搭建(二)—— 系统架构设计6之zustand状态管理
后台系统从零搭建(二)—— 系统架构设计7之菜单和路由的关联
后台系统从零搭建(三)—— 具体页面之用户管理(通用的增删改查逻辑和form-render)
后台系统从零搭建(三)—— 具体页面之菜单管理和角色管理
后台系统从零搭建(三)—— 具体页面之部门管理(抽离通用的增删改查逻辑)
后台系统从零搭建(四)—— 终结篇之权限系统怎么设计-RBAC模式

本文主要介绍系统架构设计之zustand状态管理。

Zustand适合中小型项目或需要轻量级状态管理的场景, 其核心特点:

  • 轻量级:API 简单,学习成本低。
  • 高性能:支持选择性订阅,避免不必要的渲染。
  • 灵活:支持异步操作、持久化、DevTools 等。

1.安装zustand

pnpm install zustand

2.创建store

src/store目录下创建user.ts文件,用于存储用户信息。

// src/store/user.ts
import { create } from 'zustand'
import { apiGetUser, type IUserInfo } from '@/service/user'

type IUserState = {
  user: IUserInfo
}
type IUserAction = {
  setUser: (user: IUserInfo) => void
  resetUser: () => void
  fetchUser: () => Promise<void>
}
type IUserStore = IUserState & IUserAction

// 初始状态
const userInit: IUserInfo = {
  name: '',
  email: '',
}

// 创建 store
export const useUserStore = create<IUserStore>((set) => ({
  user: { ...userInit },
  setUser: (user) => set({ user }),
  resetUser: () => set({ user: userInit }),
  fetchUser: async () => {
    try {
      const res = await apiGetUser()
      set({ user: res })
    } catch (error) {
      console.error('Failed to fetch user:', error)
    }
  },
}))

/**
 * 使用的时候
 * import { useUserStore } from '@/store/user'
 * import { shallow } from 'zustand/shallow'
 * // 只订阅 user 状态
 * const user = useUserStore((state) => state.user)
 * // 只订阅 setUser 方法
 * const setUser = useUserStore((state) => state.setUser)
 * // 订阅多个状态,使用 shallow 避免不必要的重渲染
 * const { user, setUser } = useUserStore((state) => ({
 *   user: state.user,
 *   setUser: state.setUser,
 * }))
 * // 订阅所有状态
 * const state = useUserStore()
 */

用户信息的api,因为是全局的所以放在src/service/user.ts中。

import request from '@/utils/request'

export type IUserInfo = {
  id?: number
  name: string
  email: string
  role?: string
  _id?: string
  deptId?: string
  state?: number
  roleList?: string[]
  createId?: string
  deptName?: string
  mobile?: string
  job?: string
  avatar?: string
  introduction?: string
  username?: string
}

export const apiGetUser = (): Promise<IUserInfo> => {
  return request.get('/api/userInfo')
}
export default {
  apiGetUser,
}

3.获取用户信息,保存在store中

项目启动的时候,获取用户信息,保存在store中。

这边在App.tsx中获取用户信息。

import { useUserStore } from '@/store/user'
import { useEffect } from 'react'

function App() {
  useEffect(() => {
    const fetchUser = useUserStore((state) => state.fetchUser)
    fetchUser()
  }, [])
  // ...
}

4.使用用户信息

NavHeader组件中使用用户信息。

// src/layout/NavHeader/index.tsx
import { useUserStore } from '@/store/user'
import { shallow } from 'zustand/shallow'
// ...
const user = useUserStore((state) => state.user)
const resetUser = useUserStore((state) => state.resetUser)
const menuItems: MenuProps['items'] = [
  {
    label: '退出登录',
    key: '1',
    onClick: () => {
      resetUser()
      localStorage.setItem('token', '')
      location.href = '/login?callback=' + encodeURIComponent(location.href)
    },
  },
]
// 下面的name和email就是替换成用户信息

auth_page2.gif