news 2026/6/19 22:11:07

pinia状态管理在vue3项目中的用法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pinia状态管理在vue3项目中的用法详解

Pinia 是 Vue3 官方推荐的状态管理库(替代 Vuex),相比 Vuex 更简洁、轻量化,原生支持组合式 API,无嵌套模块限制,且完美兼容 Vue DevTools。下面时pinia官方的介绍:


下面介绍一下 Pinia这款状态管理工具的完整用法,实际项目在的大多数场景可以直接照着代码改一下就可以用了。

一、核心优势(为什么选 Pinia)

  1. 无需嵌套模块,天然支持「扁平化模块化」;
  2. 抛弃mutation(仅需state/getters/actions),简化状态修改逻辑;
  3. 原生支持 TypeScript,类型提示更友好;
  4. 支持组合式 API(setup)和选项式 API 两种写法;
  5. 体积更小(约 1KB),性能更优;
  6. 完美兼容 Vue DevTools(支持时间旅行、状态追踪)。

二、基础安装

# npmnpminstallpinia# yarnyarnaddpinia# pnpmpnpmaddpinia

三、全局挂载 Pinia 实例

main.js中创建并挂载 Pinia 实例(所有组件可共享 Store):

// src/main.js (Vue3 + Vite)import{createApp}from'vue';import{createPinia}from'pinia';// 导入 PiniaimportAppfrom'./App.vue';constapp=createApp(App);constpinia=createPinia();// 创建 Pinia 实例app.use(pinia);// 挂载到 Vue 应用app.mount('#app');

四、定义 Store(核心)

Pinia 中「Store」是状态管理的核心单元,每个业务模块(如用户、购物车)对应一个独立的 Store。
支持两种写法:选项式 API(类似 Vuex)组合式 API(更灵活)

1. 选项式 API 写法(推荐新手)
// src/stores/counterStore.jsimport{defineStore}from'pinia';// 第一个参数:Store 唯一标识(必须唯一),第二个参数:配置对象exportconstuseCounterStore=defineStore('counter',{// 1. 状态:返回初始值的函数(类似 Vue 的 data)state:()=>({count:0,title:'Pinia 计数器',userInfo:{name:'张三',age:20}}),// 2. 计算属性:类似 Vue 的 computed,缓存结果getters:{// 基础用法:基于 state 计算doubleCount:(state)=>state.count*2,// 依赖其他 getter(通过 this 访问)doubleCountPlusOne(){returnthis.doubleCount+1;},// 带参数的 getter(返回函数)getCountByMultiplier:(state)=>(multiplier)=>{returnstate.count*multiplier;}},// 3. 方法:支持同步/异步,修改状态(类似 Vue 的 methods)actions:{// 同步修改increment(){this.count++;// 直接修改 state,无需 mutation},// 带参数的同步方法incrementBy(num){this.count+=num;},// 异步方法(如接口请求)asyncfetchData(){constres=awaitfetch('https://api.example.com/count');constdata=awaitres.json();this.count=data.count;// 异步修改状态},// 调用其他 actionasyncfetchAndIncrement(){awaitthis.fetchData();// 调用自身异步 actionthis.increment();// 调用同步 action}}});
2. 组合式 API 写法(推荐 Vue3 组合式项目)

更灵活,可复用组合式函数(composables):

// src/stores/counterStore.jsimport{defineStore}from'pinia';import{ref,computed}from'vue';// 组合式 API 写法:返回函数exportconstuseCounterStore=defineStore('counter',()=>{// 1. 状态:等价于 state(用 ref/reactive 定义)constcount=ref(0);consttitle=ref('Pinia 计数器');constuserInfo=ref({name:'张三',age:20});// 2. 计算属性:等价于 getters(用 computed 定义)constdoubleCount=computed(()=>count.value*2);constdoubleCountPlusOne=computed(()=>doubleCount.value+1);constgetCountByMultiplier=(multiplier)=>count.value*multiplier;// 3. 方法:等价于 actions(普通函数)constincrement=()=>{count.value++;};constincrementBy=(num)=>{count.value+=num;};constfetchData=async()=>{constres=awaitfetch('https://api.example.com/count');constdata=awaitres.json();count.value=data.count;};// 必须返回需要暴露的状态/方法return{count,title,userInfo,doubleCount,doubleCountPlusOne,getCountByMultiplier,increment,incrementBy,fetchData};});

五、组件中使用 Store

1. 基础使用(组合式 API 组件)
<!-- src/components/Counter.vue --> <template> <div> <h3>{{ counterStore.title }}</h3> <p>当前计数:{{ counterStore.count }}</p> <p>双倍计数:{{ counterStore.doubleCount }}</p> <p>三倍计数:{{ counterStore.getCountByMultiplier(3) }}</p> <button @click="counterStore.increment">+1</button> <button @click="counterStore.incrementBy(5)">+5</button> <button @click="counterStore.fetchData">异步获取计数</button> <button @click="resetCount">重置计数</button> </div> </template> <script setup> // 1. 导入 Store 函数 import { useCounterStore } from '@/stores/counterStore'; // 2. 创建 Store 实例(Pinia 会自动复用单例,多次调用也返回同一个实例) const counterStore = useCounterStore(); // 3. 直接修改状态(Pinia 默认允许,可通过严格模式禁止) const resetCount = () => { counterStore.count = 0; }; </script>
2. 解构 Store 保持响应式(关键)

直接解构 Store 会丢失响应式,需用storeToRefs辅助:

<script setup> import { useCounterStore } from '@/stores/counterStore'; import { storeToRefs } from 'pinia'; // 导入辅助函数 const counterStore = useCounterStore(); // 错误:解构后丢失响应式 // const { count, doubleCount } = counterStore; // 正确:用 storeToRefs 解构,保留响应式 const { count, doubleCount, title } = storeToRefs(counterStore); // actions 方法无需解构(本身是函数,不涉及响应式) const { increment, fetchData } = counterStore; </script> <template> <div> <p>{{ title }}</p> <p>{{ count }}</p> <p>{{ doubleCount }}</p> <button @click="increment">+1</button> <button @click="fetchData">异步获取</button> </div> </template>
3. 选项式 API 组件中使用
<script> import { useCounterStore } from '@/stores/counterStore'; import { mapState, mapActions } from 'pinia'; // 导入映射辅助函数 export default { computed: { // 映射 state/getters 到计算属性 ...mapState(useCounterStore, ['count', 'doubleCount', 'title']) }, methods: { // 映射 actions 到方法 ...mapActions(useCounterStore, ['increment', 'fetchData']) }, mounted() { console.log(this.count); // 访问状态 this.increment(); // 调用方法 } }; </script>

六、模块化(多 Store 管理)

Pinia 天然支持模块化,每个业务模块对应一个独立的 Store,无需嵌套:

src/stores/ ├── counterStore.js // 计数器 Store ├── userStore.js // 用户 Store ├── cartStore.js // 购物车 Store
示例:用户 Store
// src/stores/userStore.jsimport{defineStore}from'pinia';exportconstuseUserStore=defineStore('user',{state:()=>({token:'',userInfo:null,permissions:[]}),actions:{// 登录asynclogin(username,password){constres=awaitfetch('/api/login',{method:'POST',body:JSON.stringify({username,password})});constdata=awaitres.json();this.token=data.token;this.userInfo=data.userInfo;this.permissions=data.permissions;},// 退出登录logout(){this.token='';this.userInfo=null;this.permissions=[];}}});
组件中按需导入多 Store
<script setup> import { useCounterStore } from '@/stores/counterStore'; import { useUserStore } from '@/stores/userStore'; const counterStore = useCounterStore(); const userStore = useUserStore(); // 调用不同 Store 的方法 const handleLogin = async () => { await userStore.login('admin', '123456'); counterStore.increment(); }; </script>

七、进阶用法

1. 状态持久化(本地存储)

安装插件pinia-plugin-persistedstate,可以实现 Store 状态自动持久化到localStorage/sessionStorage

npminstallpinia-plugin-persistedstate
// src/main.jsimport{createApp}from'vue';import{createPinia}from'pinia';importpiniaPluginPersistedstatefrom'pinia-plugin-persistedstate';// 导入插件importAppfrom'./App.vue';constpinia=createPinia();pinia.use(piniaPluginPersistedstate);// 注册插件constapp=createApp(App);app.use(pinia);app.mount('#app');

在 Store 中开启持久化:

// 选项式 API 写法exportconstuseUserStore=defineStore('user',{state:()=>({token:'',userInfo:null}),actions:{/* ... */},persist:true,// 开启持久化(默认存储到 localStorage)});// 自定义持久化配置exportconstuseCartStore=defineStore('cart',{state:()=>({items:[]}),persist:{key:'cart-store',// 自定义存储键名storage:sessionStorage,// 存储到 sessionStoragepaths:['items'],// 仅持久化 items 字段(默认全量)},});
2. Store 间通信

一个 Store 可直接调用另一个 Store 的状态/方法:

// src/stores/cartStore.jsimport{defineStore}from'pinia';import{useUserStore}from'./userStore';// 导入其他 StoreexportconstuseCartStore=defineStore('cart',{state:()=>({items:[]}),actions:{asyncaddItem(item){constuserStore=useUserStore();// 创建其他 Store 实例if(!userStore.token){thrownewError('未登录,无法添加商品');}// 调用接口添加商品awaitfetch('/api/cart/add',{method:'POST',headers:{Authorization:userStore.token},body:JSON.stringify(item)});this.items.push(item);}}});
3. 严格模式(禁止直接修改状态)

Pinia 默认允许直接修改state,开启严格模式后,仅允许通过actions修改状态(类似 Vuex 的严格模式):

// src/main.jsimport{createPinia}from'pinia';constpinia=createPinia();// 开启严格模式(仅生产环境建议关闭)if(import.meta.env.MODE!=='production'){pinia.use(({store})=>{store.$subscribe((mutation,state)=>{// 检测是否直接修改 state(非 actions 触发)if(mutation.type==='direct'){console.warn(`[Pinia 严格模式] 禁止直接修改${store.$id}的状态:${mutation.payload}`);}});});}
4. 状态重置

调用$reset()方法重置 Store 到初始状态:

<script setup> import { useCounterStore } from '@/stores/counterStore'; const counterStore = useCounterStore(); const resetStore = () => { counterStore.$reset(); // 重置所有状态到初始值 }; </script>
5. 批量修改状态

使用$patch批量修改状态(性能更优,DevTools 会记录为一次修改):

// 方式1:对象形式counterStore.$patch({count:10,title:'新标题'});// 方式2:函数形式(支持复杂逻辑)counterStore.$patch((state)=>{state.count+=5;state.userInfo.age+=1;});

八、调试技巧

  1. Vue DevTools:Pinia 完美兼容 DevTools,可在「Pinia」面板查看所有 Store 的状态,支持「时间旅行」(回溯状态修改记录);
  2. $subscribe 监听状态变化
    constcounterStore=useCounterStore();// 监听状态变化counterStore.$subscribe((mutation,state)=>{console.log('状态变化:',mutation.type,mutation.payload,state);});
  3. $onAction 监听 action 调用
    counterStore.$onAction(({name,args,after,onError})=>{console.log(`开始执行 action:${name},参数:${args}`);after((result)=>{console.log(`action${name}执行成功,结果:${result}`);});onError((error)=>{console.error(`action${name}执行失败:${error}`);});});

九、常见问题

  1. 解构 Store 丢失响应式:用storeToRefs解构状态,方法可直接解构;
  2. Store 实例重复创建:无需担心,Pinia 会自动复用单例,多次调用useCounterStore()始终返回同一个实例;
  3. TypeScript 类型提示:选项式 API 自动推导类型,组合式 API 需手动标注(或用defineStore自动推导);
  4. SSR 适配:Pinia 原生支持 SSR,需在服务端为每个请求创建独立的 Pinia 实例,避免状态污染。

总结

Pinia 的核心用法可总结为:

  1. 安装并挂载 Pinia 实例;
  2. defineStore定义 Store(选项式/组合式);
  3. 组件中导入并创建 Store 实例,通过storeToRefs解构响应式状态;
  4. actions处理同步/异步状态修改,getters处理计算属性;
  5. 多 Store 实现模块化,插件扩展持久化、调试等能力。

相比 Vuex的繁琐,Pinia 更简洁、灵活,是 Vue3 项目状态管理的首选,建议在中大型项目中使用,小型项目可根据项目实际情况选择更加合适的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/11 0:11:10

CY5-1,5-二氨基戊烷(荧光花箐染料标记氨基戊烷结构)

CY5-1,5-二氨基戊烷&#xff08;荧光花箐染料标记氨基戊烷结构&#xff09; CY5-1,5-二氨基戊烷是一种通过 CY5 荧光染料标记 1,5-二氨基戊烷分子的功能性化合物。该化合物将 CY5 荧光基团的高亮度红色荧光特性与 1,5-二氨基戊烷的灵活骨架结合&#xff0c;使其在保留氨基戊烷…

作者头像 李华
网站建设 2026/6/15 14:30:06

必看!2025年北斗形变监测产品推荐,解锁大坝监测新高度

2025年&#xff0c;北斗形变监测产品引领了基础设施监测的新趋势。本文将探讨单北斗形变监测传感器和单北斗变形监测一体机的特点及其在实际应用中的优势。这些设备采用GNSS技术&#xff0c;能够提供精准的位移监测&#xff0c;广泛应用于大坝和桥梁等工程中。随着市场需求的增…

作者头像 李华
网站建设 2026/6/9 19:57:57

Java计算机毕设之基于springboot的视频论坛系统的设计与实现(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/18 7:30:04

软件测试必问的面试题(含答案)

1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前 3 年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自己&a…

作者头像 李华