Vue 3 全局状态管理方案对比:Pinia、Vuex 与自定义 composable

随着 Vue 3 的普及,全局状态管理方案的选择成为许多开发者关注的话题。Vue 3 带来了 Composition API,也让状态管理有了更多可能性。本文将对比三种主流方案:Pinia、Vuex 以及基于 Composition API 的自定义 composable,帮助你根据项目需求做出合适的选择。

为什么需要全局状态管理

在 Vue 应用中,组件之间经常需要共享状态。例如用户登录信息、购物车数据、主题设置等。如果仅靠 props 和事件传递,随着组件层级加深,代码会变得难以维护。全局状态管理提供了一种集中式的解决方案,让状态变更可预测、可追踪。

Vue 3 生态中,官方推荐的状态管理库从 Vuex 逐渐转向了 Pinia。但除了这两个库,我们还可以利用 Composition API 自己封装 composable 来实现轻量级的状态共享。

Pinia:新一代官方推荐

Pinia 是 Vue 官方团队推荐的状态管理库,专为 Vue 3 设计(也支持 Vue 2.7+)。它摒弃了 Vuex 中的 mutations,只保留 state、getters 和 actions,让代码更加简洁。

核心特点

  • 极简 API:没有 mutations,actions 可以直接修改 state,同步或异步均可。
  • 完整的 TypeScript 支持:类型推断非常出色,无需额外类型定义。
  • 模块化设计:每个 store 独立定义,无需嵌套模块。
  • Composition API 风格:可以像写 setup 函数一样定义 store。
  • DevTools 支持:与 Vue DevTools 深度集成,调试方便。

示例代码

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2
  },
  actions: {
    increment() {
      this.count++
    }
  }
})

在组件中使用:

<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>

<template>
  <button @click="counter.increment">{{ counter.count }}</button>
</template>

适用场景

Pinia 适合绝大多数 Vue 3 项目,尤其是中大型应用。它的学习曲线平缓,类型支持优秀,是目前最主流的选择。

Vuex:经典但逐渐退场

Vuex 是 Vue 2 时代的官方状态管理库,Vue 3 也支持 Vuex 4。它采用 Flux 架构,核心概念包括 state、getters、mutations、actions 和 modules。

核心特点

  • 严格的单向数据流:state 只能通过 mutations 修改,actions 提交 mutations。
  • 模块系统:支持嵌套模块,适合大型项目组织代码。
  • 成熟的生态:大量现有项目和文档。
  • 插件系统:支持持久化、日志等插件。

示例代码

// store/index.js
import { createStore } from 'vuex'

export default createStore({
  state: { count: 0 },
  getters: {
    double: (state) => state.count * 2
  },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => commit('increment'), 1000)
    }
  }
})

局限性

  • 样板代码多:需要定义 mutations 和 actions,即使是很简单的操作。
  • TypeScript 支持较弱:需要手动声明类型,体验不如 Pinia。
  • 概念复杂:对于新手来说,mutations 和 actions 的区分需要时间理解。
  • Vue 3 支持滞后:Vuex 4 虽然兼容 Vue 3,但官方已不再积极推荐。

适用场景

如果维护已有的 Vue 2 项目,或者团队已经熟悉 Vuex,可以继续使用。对于新项目,建议优先考虑 Pinia。

自定义 composable:轻量而灵活

Vue 3 的 Composition API 允许我们创建可复用的组合函数(composable)。对于简单的全局状态,完全可以自己封装一个 composable,而不引入额外的库。

实现方式

利用 refreactive 等响应式 API,配合模块作用域,可以实现单例状态。

// composables/useCounter.js
import { ref, computed } from 'vue'

const count = ref(0) // 模块作用域,天然单例

export function useCounter() {
  const increment = () => count.value++
  const double = computed(() => count.value * 2)

  return { count, increment, double }
}

在组件中使用:

<script setup>
import { useCounter } from '@/composables/useCounter'
const { count, increment } = useCounter()
</script>

优点

  • 零依赖:不需要安装任何库。
  • 完全可控:代码量少,逻辑清晰,适合小型项目或特定场景。
  • 灵活:可以自由组合其他 composable。
  • 类型友好:TypeScript 推断自然。

缺点

  • 缺少 DevTools 支持:无法像 Pinia/Vuex 那样在开发者工具中查看状态变更。
  • 没有插件生态:持久化、时间旅行调试等需要自己实现。
  • 团队规范依赖:需要约定命名和结构,否则容易混乱。
  • SSR 注意事项:在服务端渲染时,模块作用域的单例可能导致跨请求状态污染,需要谨慎处理。

适用场景

  • 小型项目或原型开发。
  • 只需要共享少量状态。
  • 对包体积敏感的场景。
  • 希望完全掌控状态逻辑。

三者对比总结

特性 Pinia Vuex 自定义 composable
学习曲线
TypeScript 支持 优秀 一般 优秀
样板代码 极少
DevTools 支持 支持 不支持
插件生态 丰富 丰富
适用规模 中大型 中大型 小型
官方推荐 否(维护模式) 视情况

如何选择

  • 新项目:优先选择 Pinia。它是 Vue 官方推荐,API 简洁,类型支持好,生态完善。
  • 维护旧项目:如果已使用 Vuex,可以继续保留,但新模块可以考虑逐步迁移到 Pinia。
  • 小型项目或简单共享:自定义 composable 足够,避免过度工程化。
  • 需要 SSR:Pinia 对 SSR 有良好支持,自定义 composable 需注意状态隔离。

结语

Vue 3 的状态管理方案没有绝对的好坏,关键在于匹配项目需求。Pinia 凭借简洁的 API 和优秀的 TypeScript 支持,已成为大多数场景的首选。Vuex 作为经典方案,在旧项目中仍有价值。而自定义 composable 则为轻量级需求提供了灵活的选择。理解它们的差异,能帮助你在不同场景下做出更明智的决策。

未经允许不得转载:任鹏个人博客 » Vue 3 全局状态管理方案对比:Pinia、Vuex 与自定义 composable

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏