第五章:Pinia 状态管理
Pinia 是 Vue 3 官方推荐的状态管理库相比 Vuex 更轻量、类型推断更好、支持组合式 API 写法。5.1 为什么用 Pinia对比维度Vuex 4PiniaTypeScript 支持一般需手动类型完整开箱即用API 复杂度mutation/action/module只有 state/getters/actions组合式 API不支持支持 setup storeDevTools支持支持更好的时间旅行Bundle Size~10KB~1.5KB代码分割需要配置天然支持5.2 定义 Store选项式写法Options Store// stores/counter.tsimport{defineStore}frompiniaexportconstuseCounterStoredefineStore(counter,{// state相当于 datastate:()({count:0,name:Counter}),// getters相当于 computedgetters:{doubled:(state)state.count*2,isPositive:(state)state.count0,// 引用其他 getter使用 thistripled():number{returnthis.doubled*1.5}},// actions相当于 methods支持异步actions:{increment(){this.count},asyncfetchAndSet(){constdataawaitapi.getData()this.countdata.count}}})组合式写法Setup Store推荐// stores/user.tsimport{defineStore}frompiniaimport{ref,computed}fromvueexportconstuseUserStoredefineStore(user,(){// ref → stateconstuserrefUser|null(null)consttokenref(localStorage.getItem(token)||)// computed → gettersconstisLoggedIncomputed(()!!token.value)constuserNamecomputed(()user.value?.name??游客)// function → actionsasyncfunctionlogin(email:string,password:string){constdataawaitauthApi.login({email,password})token.valuedata.token user.valuedata.user localStorage.setItem(token,data.token)}functionlogout(){user.valuenulltoken.valuelocalStorage.removeItem(token)}// 必须 return 所有东西return{user,token,isLoggedIn,userName,login,logout}})5.3 使用 Storescript setup langts import { storeToRefs } from pinia import { useCounterStore } from /stores/counter const counterStore useCounterStore() // ✅ 用 storeToRefs 解构保持响应式 const { count, doubled, isPositive } storeToRefs(counterStore) // ✅ actions 可以直接解构不是响应式无需 storeToRefs const { increment, fetchAndSet } counterStore // ❌ 错误做法直接解构 state 失去响应式 // const { count } counterStore // count 不会更新 /script template p{{ count }} × 2 {{ doubled }}/p button clickincrement1/button button clickcounterStore.$patch({ count: 10 })设为 10/button /template5.4 $patch 批量修改conststoreuseUserStore()// 方式1对象 patch简单场景store.$patch({name:新名字,email:newemail.com})// 方式2函数 patch推荐支持复杂操作store.$patch((state){state.list.push({id:Date.now(),text:新条目})state.count})5.5 持久化存储// 方案一手动import{defineStore}frompiniaimport{ref,watch}fromvueexportconstuseSettingsStoredefineStore(settings,(){constthemeref(localStorage.getItem(theme)||dark)watch(theme,(val)localStorage.setItem(theme,val))return{theme}})// 方案二pinia-plugin-persistedstate 插件importpiniaPluginPersistedstatefrompinia-plugin-persistedstatepinia.use(piniaPluginPersistedstate)defineStore(user,{/* ... */},{persist:{key:user-store,storage:localStorage,paths:[token,preferences]// 只持久化指定字段}})5.6 Store 间相互调用// stores/cart.tsimport{useUserStore}from./userexportconstuseCartStoredefineStore(cart,(){constuserStoreuseUserStore()// 直接调用其他 storeasyncfunctioncheckout(){if(!userStore.isLoggedIn){thrownewError(请先登录)}// ...}return{checkout}})章节总结知识点核心要点重要程度defineStore组合式写法更推荐灵活性更高⭐⭐⭐⭐⭐storeToRefs解构 state/getters 时必须用⭐⭐⭐⭐⭐$patch批量修改函数形式支持复杂操作⭐⭐⭐⭐持久化手动 or pinia-plugin-persistedstate⭐⭐⭐⭐Store 间调用直接在 action 中引用其他 store⭐⭐⭐⭐Demo 说明Demo 位于vue_demos/src/views/Chapter05_Pinia/PiniaDemo.vueCounter Store组合式storeToRefs、increment/reset、变更历史User Store选项式登录/登出、Getters 推导值展示Cart Store购物车增删、购物车角标跨组件共享App Header专栏链接Vue 3 全栈开发实战专栏项目源码资源点击下载项目源码