查看: 210|回复: 0

Vue3 Pinia状态管理安装配置与Store代码示例

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
Pinia是Vue官方推荐的状态管理库,原文说明它始于2019年的一次实验,目标是提供带组合式API的Vue状态管理方案;目前同时支持Vue 2和Vue 3,且不强制使用组合式API。它主要用于跨组件、跨页面共享状态,并提供Devtools、热更新、时间旅行调试、TypeScript自动补全和服务端渲染支持。与Vuex相比,Pinia最明显的变化是取消mutations:修改状态不再必须commit,action可以直接改state,同步和异步逻辑都放在action中,原文给出的代码量减少幅度为30%到50%。下面按安装挂载、Store定义、组件调用、Vuex对比和选型迁移来整理。

一、安装与挂载

安装命令:
  1. npm install pinia
  2. # 或
  3. yarn add pinia
  4. # 或
  5. pnpm add pinia
复制代码

创建实例并挂载到Vue应用:
  1. // src/store/index.js
  2. import { createPinia } from 'pinia'
  3. const pinia = createPinia()
  4. export default pinia
  5. // src/main.js
  6. import { createApp } from 'vue'
  7. import App from './App.vue'
  8. import pinia from './store'
  9. const app = createApp(App)
  10. app.use(pinia)
  11. app.mount('#app')
复制代码

这里的关键是createPinia()生成实例,再通过app.use(pinia)安装;后续组件里使用的Store都依赖这个挂载过程。

二、Option Store写法

Option Store接近Vue选项式API,适合从Vuex迁移的开发者。state返回数据对象,getters基于state派生并带缓存,actions放同步或异步方法。示例:
  1. import { defineStore } from 'pinia'
  2. export const useCounterStore = defineStore('counter', {
  3.   state: () => ({
  4.     count: 0,
  5.     name: 'Pinia'
  6.   }),
  7.   getters: {
  8.     doubleCount: (state) => state.count * 2,
  9.     message: (state) => `${state.name} says count is ${state.count}`
  10.   },
  11.   actions: {
  12.     increment() {
  13.       this.count++
  14.     },
  15.     decrement() {
  16.       this.count--
  17.     },
  18.     async fetchCount() {
  19.       const res = await fetch('/api/count')
  20.       this.count = await res.json()
  21.     }
  22.   }
  23. })
复制代码

组件中用useCounterStore()实例化,再直接访问state、getters和actions:
  1. <template>
  2.   <div>
  3.     <p>Count: {{ counter.count }}</p>
  4.     <p>Double: {{ counter.doubleCount }}</p>
  5.     <p>{{ counter.message }}</p>
  6.     <button @click='counter.increment'>+</button>
  7.     <button @click='counter.decrement'>-</button>
  8.     <button @click='counter.fetchCount'>获取远程数据</button>
  9.   </div>
  10. </template>
  11. <script setup>
  12. import { useCounterStore } from '@/store/counter'
  13. const counter = useCounterStore()
  14. </script>
复制代码

三、Setup Store写法

Setup Store直接使用ref、computed和普通函数,适合习惯Composition API的开发者。原文明确:ref()对应state,computed()对应getters,function()对应actions;必须返回所有state属性,否则会影响SSR和Devtools。示例:
  1. import { defineStore } from 'pinia'
  2. import { ref, computed } from 'vue'
  3. export const useCounterStore = defineStore('counter', () => {
  4.   const count = ref(0)
  5.   const name = ref('Pinia')
  6.   const doubleCount = computed(() => count.value * 2)
  7.   const message = computed(() => `${name.value} says count is ${count.value}`)
  8.   function increment() {
  9.     count.value++
  10.   }
  11.   function decrement() {
  12.     count.value--
  13.   }
  14.   async function fetchCount() {
  15.     const res = await fetch('/api/count')
  16.     count.value = await res.json()
  17.   }
  18.   return { count, name, doubleCount, message, increment, decrement, fetchCount }
  19. })
复制代码

组件调用方式与Option Store一致,仍然先useCounterStore(),再访问counter.count、counter.increment等。区别主要在Store定义侧:Setup Store更灵活,但返回列表要完整。

四、选项式API组件中的映射

如果Vue 3项目仍使用选项式API,可以用mapState、mapActions映射:
  1. <script>
  2. import { mapState, mapActions } from 'pinia'
  3. import { useCounterStore } from '@/store/counter'
  4. export default {
  5.   computed: {
  6.     ...mapState(useCounterStore, ['count', 'doubleCount'])
  7.   },
  8.   methods: {
  9.     ...mapActions(useCounterStore, ['increment', 'decrement'])
  10.   }
  11. }
  12. </script>
复制代码

这样组件内可以按原有选项式API方式使用state、getters和actions,不必全部改成script setup。

五、与Vuex的核心差异

原文的对比可以归纳为几个关键点:Vuex 4修改状态必须通过commit mutation,Pinia取消mutation,直接在action中修改;Vuex采用单一Store树并通过modules划分,Pinia是多Store设计,每个Store独立存在,通过import引用;TypeScript方面,Vuex需要大量手动类型声明,Pinia自动类型推导;模块化方面,Vuex依赖namespaced: true和嵌套路径,Pinia天然模块化;样板代码Vuex更多,Pinia更简洁,原文给出的减少幅度是30%到50%;学习曲线上Vuex较陡,Pinia接近Vue组件写法;热更新Pinia更友好。

Vuex 4的典型写法:
  1. const store = new Vuex.Store({
  2.   state: { count: 0 },
  3.   mutations: {
  4.     increment(state) { state.count++ }
  5.   },
  6.   actions: {
  7.     incrementAsync({ commit }) {
  8.       setTimeout(() => commit('increment'), 1000)
  9.     }
  10.   },
  11.   getters: {
  12.     doubleCount: state => state.count * 2
  13.   }
  14. })
  15. // 组件中
  16. this.$store.commit('increment')
  17. this.$store.dispatch('incrementAsync')
复制代码

Pinia对应写法:
  1. export const useCounterStore = defineStore('counter', {
  2.   state: () => ({ count: 0 }),
  3.   actions: {
  4.     increment() { this.count++ },
  5.     async incrementAsync() {
  6.       await delay(1000)
  7.       this.count++
  8.     }
  9.   },
  10.   getters: {
  11.     doubleCount: state => state.count * 2
  12.   }
  13. })
  14. // 组件中
  15. counter.increment()
  16. counter.incrementAsync()
复制代码

优缺点方面,原文认为Pinia语法简洁、无需mutations、样板代码少、TypeScript类型推导开箱即用、多Store天然模块化、轻量且热更新体验更好;不足是社区生态相对较新,插件不如Vuex丰富,学习资料也相对少。Vuex的优点是社区成熟、插件和工具丰富、学习资料多、严格单向数据流在大型项目里更可控;缺点是语法复杂、样板代码多、TypeScript支持不够友好,需要大量手动声明。

六、选型与迁移建议

新Vue 3项目优先选Pinia,原文给出的理由是Vue官方推荐、更现代、更简洁。Vue 2项目升级可以逐步迁移,也可以直接使用Pinia,因为Pinia同时支持Vue 2。大型遗留项目如果已经深度使用Vuex,建议渐进式迁移,允许Vuex与Pinia共存;原文提到的做法是新功能用Pinia,旧模块逐步迁移,并创建一个“桥接Store”,把Vuex中频繁使用的核心状态优先迁移到Pinia。中小型项目不一定需要状态管理库,ref/reactive配合provide/inject可能已经足够。

总结:Pinia的核心改动是取消mutations、让action直接修改状态并处理异步,同时用多Store和TypeScript推导降低样板代码;Option Store、Setup Store和选项式API映射三种用法覆盖了不同组件风格。对Vue 3新项目,按原文结论应优先考虑Pinia;对Vuex存量项目,则按渐进迁移和共存的思路处理更稳妥。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-24 14:35 , Processed in 0.022939 second(s), 28 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部