从 Pinia 到 Zustand:我在 React 里复刻了一套用户状态管理

我是小ao,一名大二学生,正在用 React + TypeScript 开发一个名为"面试克星"的 AI 面试准备平台。在此之前,我用 Vue 3 + Pinia 独立完成过一个全栈论坛项目。切换到 React 技术栈后,我遇到的第一个需要"翻译"的概念就是状态管理。

为什么要用状态管理库?

在"面试克星"里,用户登录后,导航栏需要显示用户名,个人主页需要展示和编辑用户资料,路由守卫需要判断登录状态。如果只用组件内部的 useState,这些数据会在组件间传递得乱七八糟。我需要一个全局的、能让所有组件共享的用户状态中心。

在 Vue 里我有 Pinia,在 React 里我选了 Zustand------它轻量、API 简单,而且和 Pinia 的心智模型非常接近。

Zustand vs Pinia:核心概念对照

概念 Pinia (Vue) Zustand (React)
创建 Store defineStore('auth', { state, actions }) create<State>((set) => ({ ... }))
读取状态 const auth = useAuthStore() const user = useUserStore((s) => s.user)
修改状态 直接修改 this.user = xxx 调用 set({ user: xxx }) 传入新状态
异步操作 在 actions 里写 async 函数 在 Store 内部直接写 async 函数

最大的差异在于状态的更新方式。Pinia 借助 Vue 的响应式系统,你可以直接修改状态(像改普通对象一样)。Zustand 则遵循 React 的不可变数据原则,你必须通过 set 返回一个新的状态对象。

我设计的 useUserStore

我的 Store 需要管理用户信息、JWT Token、登录状态,并提供登录、注册、退出、更新信息的方法。在用 TypeScript 之后,我发现必须先定义一个 interface,把数据和方法签名提前写好。这比 JS 版本的 Pinia 多了一道工序,但它成了我 Store 的自文档。

typescript 复制代码
interface UserState {
  user: { _id: string; username: string; email: string; ... } | null;
  token: string | null;
  isLogin: boolean;
  login: (email: string, password: string) => Promise<void>;
  register: (email: string, password: string) => Promise<void>;
  loginOut: () => void;
  updateUser: (fields: Partial<...>) => Promise<void>;
}

初始化时,我会从 localStorage 读取 token,如果存在就将 isLogin 设为 true。这样刷新页面后,登录状态不会丢失。

login 方法通过 axios 向后端发送请求,拿到 token 和 user 后,用 set({ user, token, isLogin: true }) 一次性更新 Store。register 同理,成功后只更新 user,因为注册后不自动登录。

updateUser 是我在个人主页实现内联编辑时加的。用户修改年龄、性别等字段后,我会先调后端 PUT /api/users/me 接口,成功后再用 set 更新本地 Store。这保证了前端展示与数据库同步。

那一层 interface,是负担还是助手?

刚开始写 TS 时,我觉得每个 Store 都要写一个长长的接口很麻烦。后来有一次,我在组件里不小心写错了状态名(user.username 打成了 user.userName),TypeScript 立刻在编辑器里划了红线。我突然明白了------这层 interface 不是负担,它是在我出错之前就帮我揪出 bug 的"安全网"。

从 Pinia 到 Zustand,换的是框架,不变的是对"集中管理状态、驱动视图更新"这一模式的理解。真正花时间的,从来不是学习某个库的 API,而是理解"状态管理"本身。

相关推荐
szarron16 分钟前
VNA6 便携式矢量网络分析仪|1MHz‑6.3GHz 手持 VNA 真实应用场景全解析
前端·嵌入式硬件·信息可视化·数据挖掘·数据分析
Reisentyan17 分钟前
B站首页,点击视频卡片之后首页自动刷新的问题
前端
默_笙25 分钟前
🚕 缺料就出门买:给 RAG 装上"信息够不够"的判断力
前端·javascript
Liora_Yvonne41 分钟前
同样用 Element Plus,为什么你的后台总有一股“模板味”?
前端
葡萄城技术团队1 小时前
用 Sheet 页导航视图管理复杂 SpreadJS 工作簿
前端
志尊宝1 小时前
Vue3 零基础每日笔记(054):Pinia 三件套详解——state / getters / actions 全搞懂
前端·javascript·vue.js·vue·前端开发
Caroline5161 小时前
GPT Image 2.5还能这么玩!一套提示词生成IP吉祥物,附完整案例
前端·gpt·tcp/ip
wangyadong3171 小时前
# el-table 复选框无法选中问题记录
前端·javascript·vue.js
葡萄城技术团队1 小时前
给 SpreadJS 单元格装上自动完成
前端
恋猫de小郭2 小时前
Flutter 多窗口重要优化合并,多窗口性能和实用性大幅提升
android·前端·flutter