Vue 中 Pinia 和 Vuex 有什么区别该用哪个一句话总结Pinia 是 Vue 3 官方推荐的状态管理库比 Vuex 更轻、更简洁、TypeScript 支持更好。新项目直接 Pinia老项目逐步迁移别犹豫正文目录Pinia 和 Vuex 的核心区别5 大高频踩坑场景 迁移代码万能兜底Pinia 标准 Store 模板预防 checklist不再踩坑一句话总结一、Pinia 和 Vuex 的核心区别对比项Vuex 4PiniaVue 版本Vue 2 / Vue 3Vue 2 / Vue 3Store 定义state getters mutations actionsstate getters actions无 mutationsTypeScript 支持一般需要大量类型断言优秀自动类型推断模块化需要modules嵌套每个 Store 独立天然扁平Composition API需要适配原生支持 setup 语法体积~10KB~6KBDevTools 支持✅✅学习成本高mutations 概念冗余低直觉式 API一句话Pinia 砍掉了 mutations每个 Store 独立定义setup 语法天然支持TS 类型自动推断。新项目无脑选 Pinia。二、5 大高频踩坑场景 迁移代码① Vuex 习惯修改 state 必须走 mutations// ❌ Vuex 习惯修改 state 必须写 mutationconststore{state:()({count:0}),mutations:{increment(state){state.count;}},actions:{asyncIncrement({commit}){commit(increment);// ❌ Pinia 不需要 commit}}};// 组件里this.$store.commit(increment);// ❌ Pinia 没有 commit修复Pinia 直接改 stateactions 里直接操作// ✅ Pinia直接改不需要 mutationsimport{defineStore}frompinia;exportconstuseCounterStoredefineStore(counter,{state:()({count:0}),actions:{increment(){this.count;// ✅ 直接改不需要 commit},asyncIncrement(){this.count;// ✅ action 里也可以直接改}}});// 组件里constcounteruseCounterStore();counter.increment();// ✅ 直接调counter.count10;// ✅ 也可以直接改② Vuex 模块嵌套太深取数据一长串// ❌ Vuex 模块嵌套取数据路径太长conststore{modules:{user:{modules:{profile:{state:()({name:张三}),namespaced:true}}}}};// 组件里this.$store.state.user.profile.name;// ❌ 路径太长this.$store.commit(user/profile/setName,李四);// ❌ 命名空间拼接修复Pinia 每个 Store 独立扁平化// ✅ Pinia每个 Store 独立定义exportconstuseUserStoredefineStore(user,(){constnameref(张三);constsetName(val){name.valueval;};return{name,setName};});// 组件里直接用constuserStoreuseUserStore();userStore.name;// ✅ 直接访问userStore.setName(李四);// ✅ 直接调用③ 用 setup 语法时 Vuex 类型推断差// ❌ Vuex TypeScript类型推断差需要大量断言import{useStore}from/store;conststoreuseStore();constcountstore.state.count;// ❌ 类型是 anyconstuserstore.state.user.nameasstring;// ❌ 手动断言修复Pinia 自动类型推断// ✅ Pinia自动类型推断import{useUserStore}from/stores/user;constuserStoreuseUserStore();userStore.name;// ✅ 自动推断 stringuserStore.setName(李四);// ✅ 参数类型自动校验// ✅ setup 风格的 Storeimport{defineStore}frompinia;import{ref,computed}fromvue;exportconstuseUserStoredefineStore(user,(){constnamerefstring(张三);constagerefnumber(18);constinfocomputed(()${name.value},${age.value}岁);constsetName(val:string){name.valueval;};return{name,age,info,setName};});④ Pinia 持久化刷新后状态丢失// ❌ Pinia 默认不持久化刷新页面状态丢失exportconstuseUserStoredefineStore(user,(){consttokenref();constlogin(t){token.valuet;};return{token,login};});// 刷新页面 → token 变回空字符串 ❌修复方案一手动 localStorage// ✅ 在 action 里手动存exportconstuseUserStoredefineStore(user,(){consttokenref(localStorage.getItem(token)||);constlogin(t){token.valuet;localStorage.setItem(token,t);// ✅ 存};constlogout(){token.value;localStorage.removeItem(token);// ✅ 清};return{token,login,logout};});修复方案二用 pinia-plugin-persistedstate 插件// ✅ 插件自动持久化import{createPinia}frompinia;importpiniaPluginPersistedstatefrompinia-plugin-persistedstate;constpiniacreatePinia();pinia.use(piniaPluginPersistedstate);// ✅ 全局注册// Store 里声明 persistexportconstuseUserStoredefineStore(user,{state:()({token:,user:null}),persist:true,// ✅ 自动持久化整个 state});⑤ Pinia 解构丢失响应式!-- ❌ 解构后丢失响应式 -- script setup import { useUserStore } from /stores/user; const userStore useUserStore(); const { name, age } userStore; // ❌ 解构后不是响应式的 /script template div{{ name }}/div !-- ❌ name 变了页面不更新 -- /template修复用 storeToRefs!-- ✅ 用 storeToRefs 解构保持响应式 -- script setup import { storeToRefs } from pinia; import { useUserStore } from /stores/user; const userStore useUserStore(); const { name, age } storeToRefs(userStore); // ✅ 响应式保留 // actions 可以直接解构函数不需要响应式 const { setName } userStore; /script template div{{ name }}/div !-- ✅ name 变了页面更新 -- /template三、万能兜底Pinia 标准 Store 模板Option 风格类似 Vuex适合简单 Storeimport{defineStore}frompinia;exportconstuseCounterStoredefineStore(counter,{state:()({count:0,history:[],}),getters:{double:(state)state.count*2,historyLength:(state)state.history.length,},actions:{increment(){this.count;this.history.push(1);},decrement(){this.count--;this.history.push(-1);},reset(){this.count0;this.history[];},},});Setup 风格Composition API推荐import{defineStore}frompinia;import{ref,computed}fromvue;exportconstuseUserStoredefineStore(user,(){// stateconstuserref(null);consttokenref();// gettersconstisLoggedIncomputed(()!!token.value);constuserNamecomputed(()user.value?.name||游客);// actionsconstloginasync(credentials){constresawaitfetch(/api/login,{method:POST,body:JSON.stringify(credentials),});constdataawaitres.json();token.valuedata.token;user.valuedata.user;};constlogout(){token.value;user.valuenull;};constupdateUser(patch){user.value{...user.value,...patch};};return{// stateuser,token,// gettersisLoggedIn,userName,// actionslogin,logout,updateUser,};});组件里使用script setup import { storeToRefs } from pinia; import { useUserStore } from /stores/user; const userStore useUserStore(); // ✅ 响应式数据用 storeToRefs const { user, token, isLoggedIn, userName } storeToRefs(userStore); // ✅ actions 直接解构 const { login, logout, updateUser } userStore; // ✅ 也可以直接用 $patch 批量更新 const updateProfile () { userStore.$patch({ user: { name: 新名字 } }); }; // ✅ $reset 重置仅 Option 风格支持 const resetAll () userStore.$reset(); /script四、预防 checklist新项目直接用 Pinia不要用 VuexPinia没有 mutationsactions 里直接this.xxx val修改 state每个 Store独立定义不需要 modules 嵌套组件里解构 Store 数据必须用 storeToRefs否则丢失响应式actions/methods可以直接解构函数不需要响应式持久化用 pinia-plugin-persistedstate插件或手动 localStorage推荐用setup 风格定义 StoreComposition APITS 支持更好跨 Store 调用在 action 里useOtherStore()即可$patch批量更新比逐个赋值性能更好$reset()只在 Option 风格 Store 中可用setup 风格需手动实现五、一句话总结「Pinia 更轻更直觉的 Vuex」。砍掉 mutations、扁平化 Store、setup 语法原生支持、TS 自动推断。新项目无脑 Pinia解构用 storeToRefs持久化用插件。状态管理就该这么简单最后问候亲爱的朋友们并邀请你们阅读我的全新著作 《Vue.js 3企业级项目开发实战微课视频版》