再来聊聊,Vue3 项目中 Pinia 的替代方案

想获取更多2025年最新前端场景题可以看这里fe.ecool.fun

大家好,我是刘布斯。

之前转载了一篇文章Vue 项目不要再用 Pinia 了 ,先不可否认,这文章有点标题党的意思。但这篇文章的主要观点是说,在中小项目里,用 Vue 3 自带的组合式 API(reactive / ref)来管状态,很多时候比硬上 Pinia 要香。

好家伙,评论区一下就热闹了,总结起来是:"Pinia 多好用,你肯定是没用明白 Pinia"

说实话,我确实有点意外。

我先摆明态度:Pinia 是个非常优秀的状态管理库。 尤雨溪团队亲自操刀,API 设计简洁,TS 支持完美,插件系统灵活,Devtools 体验丝滑。这一点,没人能否认。

但我的核心观点是:优秀,不代表"所有场景都必须上"。

我发现现在很多团队,尤其是从 Vue 2 刚迁到 Vue 3 不久的,存在一种很强的 "状态管理惯性"

什么意思?

在 Vue 2 + Options API 的时代,组件(Component)和状态(State)是"隔离"的。data 里的状态天生就是"内向"的,组件一销毁,状态就没了。跨组件通信、全局状态共享,你怎么办?你没得选,你必须上 Vuex。Vuex 就像一个"中央空调",你不用它,别的房间(组件)就享受不到冷气(状态)。

所以,Vue 2 时代养成了我们的思维定式:做项目 = Vue 全家桶 = Vue + Vue Router + Vuex。

到了 Vue 3,Vuex 退位,Pinia 继任。于是大家理所当然地把公式换成了:做项目 = Vue 3 + Vue Router + Pinia。

启动一个新项目,npm create vue@latest,一路 yes 下来,Pinia 就装好了。然后就开始 defineStore

但大家好像都忽略了 Vue 3 最大的革命性变化------组合式 API (Composition API) 本身,就已经是一种强大的状态管理模式了。

defineStore 帮我们做了什么?

还是用那篇文章中的例子,做一个最简单的"用户状态管理",两种方式有什么区别。

1. Pinia 的方式: 你得先在 stores/user.ts 里:

javascript 复制代码
import { defineStore } from'pinia'
import { ref, computed } from'vue'

exportconst useUserStore = defineStore('user', () => {
// State
const token = ref(null)
const userProfile = ref(null)

// Getters
const isLoggedIn = computed(() => !!token.value)

// Actions
function login(data) {
    token.value = data.token
    userProfile.value = data.profile
    // ... 存 localstorage
  }

function logout() {
    token.value = null
    userProfile.value = null
    // ... 清 localstorage
  }

return { token, userProfile, isLoggedIn, login, logout }
})

然后在组件里 useUserStore()

2. 组合式 API 的方式: 你在 stores/user.ts (对,你也可以叫 stores 目录,这只是个文件夹):

javascript 复制代码
import { ref, computed, reactive } from'vue'

// 以前我们用 reactive,这里用 ref/computed 模拟 Pinia 的结构
const token = ref(null)
const userProfile = ref(null)

const isLoggedIn = computed(() => !!token.value)

function login(data) {
  token.value = data.token
  userProfile.value = data.profile
// ... 存 localstorage
}

function logout() {
  token.value = null
  userProfile.value = null
// ... 清 localstorage
}

// 导出一个 hook
exportfunction useUser() {
return { token, userProfile, isLoggedIn, login, logout }
}

然后在组件里 useUser()


好了,你对比下这两段代码。

你发现了什么?

在第二种方式里,我只是删掉了 defineStore('user', ...) 那层"壳",然后把导出的 useUserStore 改成了 useUser (叫什么都行)。

其他的逻辑,一模一样! 都是在用 refcomputed

Pinia 的 defineStore 在这个场景里,本质上就是帮你做了一件事:创建了一个跨组件共享的、响应式的单例。

但在 Vue 3 里,import 一个在模块顶层(module scope)定义的 refreactive 对象,它天生就是单例!它天生就是跨组件共享的!

那你可能会反问了:"那 Pinia 岂不是多此一举?"

不,它当然不是多此一举。它提供了 defineStore 这个"壳",是为了给你带来额外的好处,最核心的就是:

  1. Devtools 集成 :这是 Pinia 最大的杀手锏。你可以在时间轴上看到 action 的调用、state 的变更。
  2. 插件系统 :比如实现数据持久化,Pinia 有现成的插件,defineStore 的时候配置一下就行。
  3. SSR 支持:在服务端渲染时,Pinia 能帮你处理好状态的序列化和"注水"(hydration)。
  4. 更严格的"心智模型" :它强制你区分 stategettersactions,让团队协作更规范。

Pinia的优势,你的项目真的需要吗?

我们再回到上篇文章的核心观点:

在一个中小型项目、独立开发、或者团队成员对组合式 API 都很熟练的场景下,上面 Pinia 提供的 4 个好处,你真的都需要吗?

  • Devtools :说实话,在我十多年的生涯里,除了在 Redux/Vuex 刚出来那会儿,为了调试复杂的异步流和中间件,会去用时间旅行。在绝大多数业务场景里,console.log 和 Vue Devtools 里自带的组件状态检查,已经解决了 99% 的问题。为了那 1% 的"可能",去引入一个库,划算吗?
  • 插件系统(如持久化) :用组合式 API 怎么做持久化?太简单了。你封装的 useUser hook 里面,login 的时候加一行 localStorage.setItem,初始化 token 的时候加一行 localStorage.getItem。这不就是最原始、最可控的持久化吗?你需要为这么点功能,去学一个 Pinia 插件的 API 吗?
  • SSR:如果你的项目压根就不是 SSR,那这条对你无效。
  • 严格的心智模型 :这是最大的"陷阱"。组合式 API 的核心思想就是"自由"。它允许你把 stateaction 放在一起,按"功能"去组织代码,而不是按"类型"(state/getter/action)去组织。defineStore 某种程度上,是又把我们拉回了 Vuex 的那种"分门别类"的思维里。

所以,"你会得到更少的心智负担"指的就是这个。

你不需要去记 defineStore 的 API,不需要去想"我这个逻辑是算 getter 还是 action",你就是在写 JS/TS,你就是在写 function这难道不是一种解放吗?

什么叫"没用明白 Pinia"?

在我看来,恰恰相反。

把 Pinia 当成新时代的 Vuex,不分场景、启动项目就先装上,这才是"没用明白 Vue 3"。

如果没有明白 Vue 3 组合式 API 到底给了你多大的"自由"和"能力",就可能继续用 Vue 2 的"保姆式"思维在写 Vue 3。

我想了几个场景,大家参考下:

  1. 场景一:个人项目、小团队敏捷开发、内部工具
  • 我的选择:100% 使用组合式 API。
  • 理由: 速度快,灵活,零依赖。我可以按功能拆分 useCounter.ts, useUser.ts, useCart.ts... 它们就是一堆 TS 模块,需要共享就在顶层定义 reactive,不需要就只导出函数。打包体积更小,心智负担为零。
  1. 场景二:大型企业级应用、多团队协作、需要强规范
  • 我的选择:我会倾向于使用 Pinia。
  • 理由: 这种项目,"规范"大于"灵活"。defineStore 提供的统一范式,能让不同水平的开发者(尤其是新人)写出风格更一致的代码。而且在这种复杂项目里,Devtools 的时间旅行和状态快照,在排查深层 Bug 时,确实能派上用场。
  1. 场景三:需要 SSR 的项目
  • 我的选择:用 Pinia。
  • 理由: 别重复造轮子。Pinia 对 SSR 状态处理得很好,自己搞一套组合式 API 的 SSR 状态同步,费时费力,不值得。

所以你看,并不是在全盘否定 Pinia,而是在呼吁大家 "按需选择"

不要因为"大家都用"或者"官方推荐"就去用。工具是死的,人是活的。Vue 3 给了我们一把更轻、更快的匕首(组合式 API),你为什么非要抱着那把很牛、但也很重的开山刀(Pinia)不放,连切个水果都要用它呢?

下次在项目里 npm install pinia 之前,先停 5 秒钟,问问自己:我这次,真的需要它吗?还是说,几个 refreactive 就能搞定了?

想明白这个问题,可能比你多刷 10 篇 Pinia 的教程都有用。

行了,今天就聊到这。

相关推荐
好学且牛逼的马1 小时前
【MyBatis-Plus | 常见问题与面试重点】
面试·mybatis
柒昀2 小时前
Vue.js
前端·javascript·vue.js
2201_757830872 小时前
Stream的终结方法
java·服务器·前端
进阶的鱼2 小时前
React+ts+vite脚手架搭建(五)【登录篇】
前端·javascript
safestar20122 小时前
React深度实战:从组件抽象到性能优化的思考历程
前端·javascript·react.js
洗澡水加冰2 小时前
VSCode插件: 自动临时分配Theme以区分不同窗口
前端·typescript·visual studio code
我叫张小白。2 小时前
TypeScript类型断言与类型守卫:处理类型的不确定性
前端·javascript·typescript
阿笑带你学前端2 小时前
Flutter 实战:为开源记账 App 实现优雅的暗黑模式(Design Token + 动态主题)
前端
天渺工作室2 小时前
Chrome浏览器自带翻译的诡异Bug:ID翻译后竟然变化了
前端·chrome