news 2026/4/15 7:35:24

Pinia 完整使用指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Pinia 完整使用指南

Pinia 是 Vue 官方推荐的状态管理库,用于跨组件、跨页面共享状态,其功能定位与 Vuex 一致,但具备更简洁的 API 设计、更好的 TypeScript 支持,且移除了 Vuex 中繁琐的 mutations 概念,大幅降低了学习与使用成本。作为 Vuex 的替代方案,Pinia 更轻量、灵活,是 Vue 3 项目状态管理的首选方案。

二、安装 Pinia

支持 yarn、npm、pnpm 三种包管理器安装,选择任意一种即可:

yarnaddpinia# 或使用 npmnpminstallpinia# 或使用 pnpmpnpmaddpinia

安装完成后,重启项目使依赖生效。

三、Pinia 封装

3.1 封装目的

将 Pinia 实例创建、持久化插件引入等统一管理,避免在 main.js 中写入过多冗余代码,提升项目结构的可维护性(后续持久化插件的配置将在此基础上扩展)。

3.2 封装步骤

  1. src目录下创建stores文件夹(约定俗成的状态管理目录),并在该文件夹下创建index.js文件;

  2. index.js中创建并导出 Pinia 实例:
    `// src/stores/index.js
    import { createPinia } from “pinia”; // 引入 Pinia 核心方法

const pinia = createPinia(); // 创建 Pinia 实例

export default pinia; // 导出实例,供 main.js 注册`

  1. 在 main.js 中引入并使用 Pinia:
    `// src/main.js
    import { createApp } from ‘vue’;
    import App from ‘./App.vue’;
    import router from ‘./router’;
    import ‘./assets/reset.css’;
    import ElementPlus from ‘element-plus’;
    import pinia from ‘./stores’; // 引入封装好的 Pinia 实例

// 注意:此处修正原文重复 use(router) 的错误
createApp(App)
.use(pinia) // 注册 Pinia
.use(router) // 注册路由
.use(ElementPlus) // 注册 ElementPlus
.mount(‘#app’);`

四、定义 Store

4.1 核心规则

  • Store 通过defineStore()函数定义,第一个参数为唯一名称(id),用于连接开发者工具,不可重复;

  • 约定将返回的 Store 函数命名为useXxxStore格式(如 useUserInfoStore),符合 Vue 可组合项的命名规范;

  • Store 文件建议放在stores目录下,文件名见名知意(如用户相关状态用 user.js)。

4.2 具体实现(以用户状态为例)

  1. stores目录下创建user.js文件;

  2. 编写 Store 定义代码:
    `// src/stores/user.js
    import { defineStore } from “pinia”;

// 定义并导出用户信息 Store
const useUserInfoStore = defineStore(‘userInfo’, {
// state:存储核心状态数据,必须是函数(避免跨组件共享引用问题)
state: () => ({
username: ‘赫赫’,
age: 30,
like: ‘girl’,
obj: { money: 100, friend: 10 },
hobby: [
{ id: 1, name: ‘篮球’, level: 1 },
{ id: 2, name: ‘rap’, level: 10 }
]
})
});

export default useUserInfoStore;`

五、Store 三大核心概念

Pinia 的核心功能围绕 State、Getters、Actions 展开,分别对应「状态数据」「派生数据」「业务逻辑」三大核心场景。

5.1 State:核心状态数据

State 类似于组件中的 data,用于存储全局共享的原始数据。

5.1.1 访问 State 数据

Store 实例化后,可直接通过实例访问 State 数据,但需注意:不可直接解构 Store 实例,否则会丢失数据的响应式特性。若需解构,需使用 Pinia 提供的storeToRefs()方法(推荐)或 Vue 的toRefs()方法。

<template> <!-- 直接使用响应式数据 --> <div>我叫 {{ username }},今年 {{ age }} 岁,喜欢 {{ like }}</div> <div>爱好列表:</div> <div v-for="item in hobby" :key="item.id"> {{ item.name }}(熟练度:{{ item.level }}) </div> <button @click="editPiniaHandler">逐个修改数据</button> <button @click="editAll">批量修改数据</button> <button @click="replaceAll">替换整个 State</button> <button @click="resetBtn">重置 State</button> </template> <script setup> import { storeToRefs } from "pinia"; // 引入 Pinia 响应式解构工具 import useUserInfoStore from "@/stores/user"; // 引入用户 Store // 实例化 Store(Store 会在首次调用时创建) const userInfoStore = useUserInfoStore(); // 响应式解构 State 数据(推荐使用 storeToRefs) const { username, age, like, hobby } = storeToRefs(userInfoStore); // 错误示范:直接解构会丢失响应式 // const { username, age } = userInfoStore; </script>

5.1.2 修改 State 数据

Pinia 支持 4 种修改 State 的方式,根据场景灵活选择:

  1. 直接修改:适用于单个数据的简单修改
    // 逐个修改数据 const editPiniaHandler = () => { userInfoStore.username += "嘎"; userInfoStore.age += 1; userInfoStore.like = "boy"; };

  2. **KaTeX parse error: Expected '}', got 'EOF' at end of input: … userInfoStore.patch({
    username: “鸭蛋”,
    age: 21,
    obj: { money: 200, friend: 15 } // 注意:对象会被完整替换
    });

// 若需修改对象/数组中的部分属性,可使用函数形式
userInfoStore.$patch((state) => {
state.obj.money += 50;
state.hobby.push({ id: 3, name: ‘游泳’, level: 5 });
});
};`

  1. **KaTeX parse error: Expected '}', got 'EOF' at end of input: … userInfoStore.state = {
    username: ‘狗子’,
    age: 22,
    like: ‘boy’,
    obj: { money: 10, friend: 1 },
    hobby: []
    };
    };`

  2. **KaTeX parse error: Expected '}', got 'EOF' at end of input: … userInfoStore.reset();
    };`

5.2 Getters:派生状态数据

Getters 类似于组件中的 computed,用于基于 State 派生出新数据,具备缓存特性(依赖的 State 未变化时,多次访问会复用缓存结果)。

5.2.1 定义 Getters

在 defineStore 中与 state 同级定义,支持两种写法:接收 state 参数访问状态,或通过 this 访问其他 Getters。

// src/stores/user.jsimport{defineStore}from"pinia";constuseUserInfoStore=defineStore('userInfo',{state:()=>({username:'赫赫',age:30,like:'girl',obj:{money:100,friend:10},hobby:[{id:1,name:'篮球',level:1},{id:2,name:'rap',level:10}]}),// 定义 Gettersgetters:{// 基础用法:通过 state 参数访问状态doubleAge:(state)=>state.age*2,// 进阶用法:通过 this 访问其他 Getters(注意:不可使用箭头函数,否则 this 指向异常)addOneAge(){returnthis.doubleAge+1;},// 传参用法:返回函数实现动态传参(此时缓存失效,每次调用都会重新计算)getHobbyById:(state)=>(id)=>{returnstate.hobby.find(item=>item.id===id)||'未找到该爱好';},// 复杂派生:计算总资产(假设 money 为现金,friend 为好友数量,此处仅为示例)totalAssets(){returnthis.obj.money+this.obj.friend*10;}}});exportdefaultuseUserInfoStore;

5.2.2 使用 Getters

直接通过 Store 实例访问 Getters,传参时直接调用函数并传入参数:

<template> <div>年龄翻倍:{{ userInfoStore.doubleAge }}</div> <div>年龄翻倍+1:{{ userInfoStore.addOneAge }}</div> <div>ID=1 的爱好:{{ userInfoStore.getHobbyById(1) }}</div> <div>总资产:{{ userInfoStore.totalAssets }}</div> </template> <script setup> import useUserInfoStore from "@/stores/user"; const userInfoStore = useUserInfoStore(); </script>

5.3 Actions:业务逻辑封装

Actions 类似于组件中的 methods,用于封装业务逻辑,支持同步和异步操作,是修改 State 的推荐方式(集中管理逻辑,便于维护)。与 Vuex 不同,Pinia 的 Actions 可直接修改 State,无需通过 mutations。

5.3.1 定义 Actions

在 defineStore 中与 state、getters 同级定义,可通过 this 访问 Store 实例的 state、getters 和其他 actions。

// src/stores/user.jsimport{defineStore}from"pinia";constuseUserInfoStore=defineStore('userInfo',{state:()=>({/* 省略 state 定义 */}),getters:{/* 省略 getters 定义 */},// 定义 Actionsactions:{// 同步 Action:接收外部参数addAge(step){console.log('接收的步长参数:',step);this.age+=step;// 直接修改 Statethis.updateAssets(step);// 调用其他 Action},// 辅助 Action:更新资产(内部调用,不对外暴露)updateAssets(step){this.obj.money+=step*10;},// 异步 Action:模拟 API 请求asyncfetchUserInfo(){try{// 模拟网络请求(2 秒延迟)constres=awaitnewPromise((resolve)=>{setTimeout(()=>{resolve({username:'小明',age:25,like:'coding'});},2000);});// 更新 Statethis.$patch(res);returnres;// 向外返回结果}catch(error){console.error('获取用户信息失败:',error);throwerror;// 抛出错误,供组件捕获}},// 复杂异步场景:调用其他异步 ActionasyncloadUserAndHobby(){constuserInfo=awaitthis.fetchUserInfo();// 模拟加载爱好列表consthobbies=awaitthis.fetchHobbies(userInfo.username);this.hobby=hobbies;},// 模拟加载爱好列表fetchHobbies(username){returnnewPromise((resolve)=>{setTimeout(()=>{resolve([{id:1,name:'编程',level:8},{id:2,name:'健身',level:6}]);},1000);});}}});exportdefaultuseUserInfoStore;

5.3.2 使用 Actions

直接通过 Store 实例调用 Actions,同步 Action 直接调用,异步 Action 可使用 await 捕获结果或处理错误:

<script setup>importuseUserInfoStorefrom"@/stores/user";constuserInfoStore=useUserInfoStore();// 调用同步 Actionconstadd=()=>{userInfoStore.addAge(5);};// 调用异步 ActionconstloadUser=async()=>{try{constres=awaituserInfoStore.fetchUserInfo();console.log('获取用户信息成功:',res);}catch(error){console.error('获取失败:',error);}};// 调用依赖其他异步 Action 的方法constloadAll=async()=>{awaituserInfoStore.loadUserAndHobby();console.log('用户信息和爱好加载完成');};</script>

六、Pinia 持久化存储

默认情况下,Pinia 的 State 存储在内存中,页面刷新后会丢失。通过pinia-plugin-persistedstate插件可实现 State 持久化,支持 localStorage、sessionStorage 等存储方式。

6.1 安装持久化插件

npminstallpinia-plugin-persistedstate# 或 yarnyarnaddpinia-plugin-persistedstate# 或 pnpmpnpmaddpinia-plugin-persistedstate

6.2 注册插件

在之前封装的src/stores/index.js中引入并注册插件:

// src/stores/index.jsimport{createPinia}from"pinia";// 引入持久化插件importpiniaPluginPersistedstatefrom'pinia-plugin-persistedstate';constpinia=createPinia();// 注册插件pinia.use(piniaPluginPersistedstate);exportdefaultpinia;

6.3 持久化配置

在定义 Store 时,通过persist选项配置持久化规则,支持基础配置和高级配置两种方式。

6.3.1 基础配置(默认规则)

persist设为true,使用默认配置:

  • 存储方式:localStorage

  • 存储键名:Store 的 id(如 userInfo)

  • 序列化/反序列化:JSON.stringify / JSON.parse

  • 持久化范围:整个 State

// src/stores/user.jsimport{defineStore}from"pinia";constuseUserInfoStore=defineStore('userInfo',{state:()=>({username:'赫赫',age:30,like:'girl'}),getters:{/* 省略 */},actions:{/* 省略 */},// 开启持久化(默认配置)persist:true});exportdefaultuseUserInfoStore;

6.3.2 高级配置(自定义规则)

通过对象形式配置persist,支持自定义存储键名、存储方式、持久化字段等,核心配置项如下:

  • key:自定义存储键名(默认是 Store 的 id);

  • storage:指定存储方式(localStorage / sessionStorage);

  • paths:指定需要持久化的字段(数组形式,不指定则全量持久化);

  • serializer:自定义序列化/反序列化方法(默认 JSON 处理)。

// src/stores/user.jsimport{defineStore}from"pinia";constuseUserInfoStore=defineStore('userInfo',{state:()=>({username:'赫赫',age:30,like:'girl',obj:{money:100,friend:10},hobby:[]}),getters:{/* 省略 */},actions:{/* 省略 */},// 高级持久化配置persist:{key:'user_info_storage',// 自定义存储键名storage:sessionStorage,// 存储方式改为 sessionStorage(页面关闭后丢失)paths:['username','age','obj.money'],// 仅持久化 username、age、obj.money 字段// 自定义序列化/反序列化(可选)serializer:{serialize:(value)=>JSON.stringify(value),deserialize:(value)=>JSON.parse(value)}}});exportdefaultuseUserInfoStore;

6.3.3 多 Store 独立配置

每个 Store 可单独配置持久化规则,互不影响。例如,用户信息用 localStorage 持久化,购物车用 sessionStorage 持久化:

// 购物车 Store(src/stores/cart.js)import{defineStore}from"pinia";constuseCartStore=defineStore('cart',{state:()=>({items:[],total:0}),persist:{key:'cart_storage',storage:sessionStorage,// 购物车仅在当前会话有效paths:['items']// 仅持久化商品列表}});exportdefaultuseCartStore;

七、Pinia 两种定义方式对比

Pinia 支持两种 Store 定义方式,分别对应 Vue 的 Options API 和 Composition API 范式,可根据项目需求选择:

7.1 两种定义方式示例

// 1. Options API 风格(本文默认方式,结构化清晰,适合 Vuex 迁移)constuseUserStore=defineStore('user',{state:()=>({username:''}),getters:{fullName:(state)=>`Mr.${state.username}`},actions:{setUsername(name){this.username=name}}});// 2. Composition API 风格(灵活度高,类型推断更好,适合复杂逻辑复用)import{ref,computed}from'vue';import{defineStore}from'pinia';constuseUserStore=defineStore('user',()=>{// 状态:对应 stateconstusername=ref('');// 计算属性:对应 gettersconstfullName=computed(()=>`Mr.${username.value}`);// 方法:对应 actionsconstsetUsername=(name)=>{username.value=name;};// 必须返回需要暴露的属性和方法return{username,fullName,setUsername};});

7.2 核心区别对比

对比维度Options API 风格Composition API 风格
状态定义state 函数返回对象使用 ref/reactive 定义
计算属性getters 对象定义使用 computed 函数定义
方法定义actions 对象定义直接定义函数
类型推断一般优秀
逻辑复用较困难容易(可抽离独立函数)
适用场景简单状态、Vuex 迁移项目复杂逻辑、TypeScript 项目

八、常见问题与最佳实践

8.1 常见问题

  • 问题 1:解构 Store 后数据丢失响应式?
    解答:使用storeToRefs()替代直接解构,该方法会为 State 数据创建响应式引用。

  • 问题 2:页面刷新后 State 丢失?
    解答:开启持久化存储,通过pinia-plugin-persistedstate插件配置 localStorage 存储。

  • 问题 3:Actions 中 this 指向异常?
    解答:Actions 中的方法不可使用箭头函数,否则 this 无法指向 Store 实例。

  • 问题 4:多个组件调用同一 Action 会重复请求?
    解答:在 Action 中添加缓存逻辑,例如通过标志位判断请求是否正在进行,避免重复调用。

8.2 最佳实践

  • Store 拆分原则:按业务模块拆分(如 user.js、cart.js、setting.js),避免单个 Store 过于庞大。

  • 命名规范:Store 文件名、id 均使用小写+下划线命名(如 user_info),Store 函数名遵循useXxxStore格式。

  • 异步请求位置:需要跨组件共享的数据,异步请求放在 Actions 中;仅组件内部使用的请求,直接在组件内处理。

  • 状态修改规范:复杂逻辑的状态修改统一放在 Actions 中,便于维护和调试;简单修改可直接操作 State。

  • 开发工具使用:Pinia 内置支持 Vue DevTools,可通过开发者工具查看 State 变化、回溯 Actions 调用记录,提升调试效率。

九、参考资料

  • Pinia 官方文档:https://pinia.vuejs.org/

  • pinia-plugin-persistedstate 官方文档:https://prazdevs.github.io/pinia-plugin-persistedstate/

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

python django flask鹿幸公司员工食堂在线点餐餐饮餐桌预约管理系统的设计与实现_utcnqqs0--论文

文章目录系统截图项目技术简介可行性分析主要运用技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;系统截图 python django flask鹿幸公司员工食堂在线点餐餐饮餐桌预约管理系统的设计与实现_utcnqqs0–论文 …

作者头像 李华
网站建设 2026/4/9 15:07:47

性价比高的老房换新实用门窗品牌精选指南排名

性价比高的老房换新实用门窗品牌精选指南排名在老房换新的过程中&#xff0c;门窗的更换是至关重要的一环。选择一款性价比高的门窗&#xff0c;不仅能提升居住的舒适度&#xff0c;还能为家居增添美观。以下为大家带来一份实用的门窗品牌精选指南。工厂直营模式&#xff1a;性…

作者头像 李华
网站建设 2026/4/15 4:32:17

好用做老房换新实用门窗品牌精选指南的机构

做老房换新实用门窗的品牌精选指南引言老房换新门窗是提升居住品质的重要工程&#xff0c;然而面对众多的门窗品牌&#xff0c;消费者往往不知如何选择。在众多选择中&#xff0c;工厂直营模式的品牌有着独特的优势。专业评估能力像采用工厂直营模式的这类品牌&#xff0c;具备…

作者头像 李华
网站建设 2026/4/9 10:22:35

灵活用工平台,我的实践复盘

灵活用工平台技术实践复盘&#xff1a;从行业挑战到解决方案的演进行业痛点分析当前&#xff0c;灵活用工平台领域正面临一系列深刻的技术挑战&#xff0c;这些挑战直接关系到平台的稳定性、合规性及用户体验。首要挑战在于海量并发处理与数据精准性。随着灵活用工模式渗透率的…

作者头像 李华
网站建设 2026/4/8 20:54:31

在duckdb 递归CTE中实现深度优先搜索DFS

原帖地址 https://github.com/duckdb/duckdb/discussions/15386 通常的递归CTE都是广度优先搜索&#xff08;BFS&#xff09; WITH RECURSIVE edges(a, b) as( VALUES(1, 2),(1, 3),(2, 4),(4, 5),(4, 6) ), bfs(node, path) AS (SELECT 1 AS node, [] :: STRUCT("from&…

作者头像 李华
网站建设 2026/4/11 13:04:51

基于记忆增强网络的语言模型推理优化

基于记忆增强网络的语言模型推理优化 关键词:记忆增强网络、语言模型、推理优化、注意力机制、深度学习 摘要:本文聚焦于基于记忆增强网络的语言模型推理优化。首先介绍了相关背景,包括研究目的、预期读者、文档结构和术语定义。接着阐述了核心概念,如记忆增强网络和语言模…

作者头像 李华