从 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,而是理解"状态管理"本身。

相关推荐
Flynt1 小时前
axios 被投毒半年后,我把 npm 的"安全防线"实测了一遍:最信任的 SHA512 是安慰剂
前端·npm·node.js
excel2 小时前
Base62 和 Base64 有什么区别?
前端
风骏时光牛马3 小时前
大模型底层架构与AI源码深度剖析
前端
掘金挖土4 小时前
前端手摸手跑路之 AI 应用开发(九)
前端·后端
中文呀6 小时前
三维 GIS 离线缓存实战:逆向 CesiumOfflineCache,并亲手为它补上"自动更新"能力
前端
前进前进前进7 小时前
TRAE 全链路实战:做了一个警示牌一键生成器:纯 Canvas、单文件、零依赖
前端
小万7428 小时前
God‘s Eye View 深度解析:15 路公开信号 + CesiumJS 的浏览器级 OSINT 控制台,60 帧渲染的“真实间谍卫星模拟器”
前端
IT星宿8 小时前
浏览器标签页全是一个图标:我用名字哈希生成 favicon,让每个项目都有身份标识
前端
全栈项目管理程序猿8 小时前
ArcGIS JS 基础教程(32):体元系列 - VoxelSlice 体元切片
前端·javascript