聊聊Vuex vs Pinia
一、Vuex 的核心概念
Vuex 有五个主要模块:
-
State(状态)
-
就是数据的存放地,相当于一个全局的 data。
-
组件通过 this.$store.state.xxx 或 mapState 辅助函数来访问。
-
-
Getter(派生状态)
-
类似组件中的 computed,对 state 进行二次计算。
-
比如把购物车的商品总价计算出来。
-
-
Mutation(同步修改状态)
-
唯一可以修改 state 的方法。
-
必须是同步函数,方便调试和时间旅行(devtools 可以追踪)。
-
比如 INCREMENT(state) { state.count++ }。
-
-
Action(异步逻辑 + 提交 mutation)
-
用来处理异步操作(如请求接口),然后再通过 commit 提交 mutation。
-
比如登录接口请求成功后,再更新用户信息。
-
-
Module(模块化)
- 项目大了可以把 store 拆分成多个模块,每个模块有自己的 state、mutation、action、getter,互相独立。
使用流程(简单示例)
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},getters: {doubleCount: state => state.count * 2},mutations: {INCREMENT(state) {state.count++}},actions: {asyncIncrement({ commit }) {setTimeout(() => {commit('INCREMENT')}, 1000)}}
})
组件里用:
<template><div><p>{{ count }}</p><p>{{ doubleCount }}</p><button @click="increment">+1</button><button @click="asyncIncrement">异步+1</button></div>
</template><script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'export default {computed: {...mapState(['count']),...mapGetters(['doubleCount'])},methods: {...mapMutations(['INCREMENT']),...mapActions(['asyncIncrement']),increment() {this.INCREMENT()}}
}
</script>
二、Pinia 的核心思想
Pinia 和 Vuex 的思想是一脉相承的:
-
把组件之间共享的状态抽出来,集中到一个地方(store)管理
-
保证数据修改可控(不会随便乱改)
-
让组件用起来像访问普通对象一样方便
但 Pinia 去掉了很多繁琐的东西,让开发体验更轻量。
三、Pinia 的核心概念
-
Store(存储容器)
-
相当于一个模块,里面包含 state、getter、action
-
可以有多个 store,互相独立,天然模块化
-
-
State(状态)
-
就是数据源,写法和 Vue 组件的 data() 类似
-
支持响应式,组件中直接使用会自动更新
-
-
Getter(派生状态)
-
类似 computed,从 state 派生出新的数据
-
支持类型推导,比 Vuex 更好用
-
-
Action(方法)
-
相当于 Vue 组件里的 methods,既能处理同步,也能写异步逻辑
-
可以直接修改 state,不需要 mutation(这是 Pinia 比 Vuex 最大的简化点)
-
使用示例:定义 store(stores/counter.js)
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', {state: () => ({count: 0}),getters: {doubleCount: state => state.count * 2},actions: {increment() {this.count++},asyncIncrement() {setTimeout(() => this.count++, 1000)}}
})
在组件中使用:
<script setup>
import { useCounterStore } from '@/stores/counter'const counter = useCounterStore()
</script><template><div><p>{{ counter.count }}</p><p>{{ counter.doubleCount }}</p><button @click="counter.increment">+1</button><button @click="counter.asyncIncrement">异步+1</button></div>
</template>
对比
特点 | Vuex | Pinia |
---|---|---|
出现时间 | 2016年,Vue 官方推出 | 2021年,Vue 官方推荐的新库 |
适用版本 | Vue2 / Vue3 都支持 | Vue2(需要插件)/ Vue3 原生支持 |
核心思想 | 单一状态树(state + mutation + action + getter) | 多个 store(模块化更自然) |
定义方式 | new Vuex.Store({ ... }) | defineStore('id', { state, getters, actions }) |
Mutation | 必须写 mutation(同步修改 state) | 不需要 mutation,直接在 action 或 state 里修改 |
Action | 用于异步操作,必须 commit mutation 才能改 state | 既能处理异步,又能直接改 state(更灵活) |
Getter | getters: {} 对象形式 | 支持函数式 + 自动推断类型 |
模块化 | module 复杂,需要命名空间 | 每个 store 天然独立,无需命名空间 |
TypeScript 支持 | 类型推导差,写起来繁琐 | 原生支持 TS,类型推导非常好 |
调试工具 | Vue DevTools 完善 | Vue DevTools(新版已全面支持) |
学习成本 | 高,概念多(state/getter/mutation/action/module) | 低,更直观(state/getter/action) |
生态未来 | 逐渐被 Pinia 取代 | 官方推荐,Vuex5 也会基于 Pinia |