Vue——状态管理库Pinia
写在前面:本文参考小满大牛的pinia专栏
一、Vuex与Pinia
Vuex 和 Pinia 均是 Vue.js 的状态管理库,它们为 Vue 应用程序提供了一种集中式的、可预测的状态管理解决方案。
Vuex 是 Vue.js 官方推荐的状态管理库之一。它的核心概念包括 state、mutation、action 和 getter。其中,state 代表应用程序的状态数据,在 Vuex 中存储为唯一的来源,mutation 用于修改状态数据并确保数据变化的可追踪性,action 用于处理异步操作或组合多个 mutation 操作,getter 可以让我们对 state 进行计算和派生,并使其变得更加易于访问。一个 Vuex store 实例是一个全局 JavaScript 对象,可以在所有组件中通过注入来进行访问和操作。
Pinia 是一个新的状态管理库,也是专门为 Vue 3 开发的。它提供了一个类似于 Vuex 的状态管理模式,但采用最新的 Vue 3 API 构建。相比 Vuex,Pinia 更简单、更轻量,更加灵活,并支持 TypeScript 类型检查。
与 Vuex 相比,Pinia 没有严格的命名约定,可以自由拆分逻辑、支持独立实例、执行更轻量级的代码等。但不同于 Vuex,它并没有内置支持模块化和严格调试工具。
以下是Pinia的特点:
- 完整的 ts 的支持;
- 足够轻量,压缩后的体积只有1kb左右;
- 去除 mutations,只有 state,getters,actions;
- actions 支持同步和异步;
- 代码扁平化没有模块嵌套,只有 store 的概念,store 之间可以自由使用,每一个store都是独立的
- 无需手动添加 store,store 一旦创建便会自动添加;
- 支持Vue3 和 Vue2
Pinia官方文档
二、安装、引入Pinia
安装:npm install pinia 或 yarn add pinia
引入注册:
Vue3的引入方法
main.ts
import { createApp } from 'vue'
import App from './App.vue'
// Vue3的引入方法
import {createPinia} from 'pinia'const store = createPinia()let app = createApp(App)app.use(store)app.mount('#app')
Vue2的引入方法
main.ts
import { createPinia, PiniaVuePlugin } from 'pinia'Vue.use(PiniaVuePlugin)
const pinia = createPinia()new Vue({el: '#app',pinia,
})
三、初始化创建Store
新建文件夹

index.ts用于管理仓库,store-name.ts用于存储所有枚举的仓库名。
store-name.ts
// 枚举所有仓库名并暴露
export const enum Names {TEST = 'TEST'
}
index.ts
// 导入定义仓库的方法
import { defineStore } from "pinia";
// 导入枚举的所有仓库名
import { Names } from "./store-name";// defineStore()定义一个仓库,第一个参数作为名称,也可看作是id
// 这个id(名称)是必要的,Pinia使用它来讲store连接DevTools,可以通过调试工具查看
export const useTestStore = defineStore(Names.TEST, {state: () => {return {// 定义初始化的值current: 1,name: '小5'}},// 类似于computed可以帮我们修饰我们的值getters: {},// 可以操作异步 和 同步 提交stateactions: {}
})
简单的使用仓库的数据
App.vue
<template><div>pinia-current:{{ Test.current }}</div><div>pinia-name:{{ Test.name }}</div>
</template><script setup lang="ts">
import { useTestStore } from "./store";const Test = useTestStore();
</script><style lang="scss" scoped></style>
结果展示:

四、修改State值的五种方式
1.直接修改
State是允许不在仓库中直接修改值的,这与Vuex不同,Vuex要通过commit或dispatch方法调用仓库修改。
<template><div>pinia-current:{{ Test.current }}</div><div>pinia-name:{{ Test.name }}</div><div style="display: flex; flex-direction: column"><button @click="change">change</button></div>
</template><script setup lang="ts">
import { useTestStore } from "./store";const Test = useTestStore();const change = () => {Test.current++;
};
</script><style lang="scss" scoped></style>
2.批量修改
在仓库的实例上有$patch方法可以批量修改多个值
<template><div>pinia-current:{{ Test.current }}</div><div>pinia-name:{{ Test.name }}</div><div style="display: flex; flex-direction: column"><button @click="bulkChange">批量change</button></div>
</template><script setup lang="ts">
import { useTestStore } from "./store";const Test = useTestStore();const bulkChange = () => {Test.$patch({current: 888,name: "小4",});
};
</script><style lang="scss" scoped></style>
3.批量修改工厂函数形式
推荐使用函数形式 可以自定义修改逻辑
<template><div>pinia-current:{{ Test.current }}</div><div>pinia-name:{{ Test.name }}</div><div style="display: flex; flex-direction: column"><button @click="funChange">工厂函数实现批量change</button>
</template><script setup lang="ts">
import { useTestStore } from "./store";const Test = useTestStore();const funChange = () => {Test.$patch((state) => {(state.current = 999), (state.name = "小3");});
};
</script><style lang="scss" scoped></style>
4.通过原始对象修改整个实例
$state您可以通过将store的属性设置为新对象来替换store的整个状态
缺点就是必须修改整个对象的所有属性,可以用结构赋值的方式解决这个缺点。
<template><div>pinia-current:{{ Test.current }}</div><div>pinia-name:{{ Test.name }}</div><div style="display: flex; flex-direction: column"><button @click="allChange">必须修改全部的写法(不推荐写法)</button></div>
</template><script setup lang="ts">
import { useTestStore } from "./store";const Test = useTestStore();const allChange = () => {Test.$state = {...Test.$state,name: "小2",};
};
</script><style lang="scss" scoped></style>
5.通过actions修改
在仓库中定义Actions
在仓库的actions 中直接使用this就可以指到state里面的值
store/index.ts
import { defineStore } from "pinia";
import { Names } from "./store-name";export const useTestStore = defineStore(Names.TEST, {state: () => {return {current: 1,name: '小5'}},getters: {},// 可以操作异步 和 同步 提交stateactions: {// 不能写箭头函数 否则this会指向错误setCurrent(num:number) {this.current = num}}
})
直接在App.vue实例中调用
<template><div>pinia-current:{{ Test.current }}</div><div>pinia-name:{{ Test.name }}</div><div style="display: flex; flex-direction: column"><button @click="actionsChange">使用actions修改</button></div>
</template><script setup lang="ts">
import { useTestStore } from "./store";const Test = useTestStore();const actionsChange = () => {Test.setCurrent(555);
};
</script><style lang="scss" scoped></style>
6.结果展示
App.vue
<template><div>pinia-current:{{ Test.current }}</div><div>pinia-name:{{ Test.name }}</div><div style="display: flex; flex-direction: column"><button @click="change">change</button><button @click="bulkChange">批量change</button><button @click="funChange">工厂函数实现批量change</button><button @click="allChange">必须修改全部的写法(不推荐写法)</button><button @click="actionsChange">使用actions修改</button></div>
</template><script setup lang="ts">
import { useTestStore } from "./store";const Test = useTestStore();const change = () => {Test.current++;
};
const bulkChange = () => {Test.$patch({current: 888,name: "小4",});
};
const funChange = () => {Test.$patch((state) => {(state.current = 999), (state.name = "小3");});
};
const allChange = () => {Test.$state = {...Test.$state,name: "小2",};
};
const actionsChange = () => {Test.setCurrent(555);
};
</script><style lang="scss" scoped></style>
结果展示:

五、解构store
在Pinia是不允许直接解构state的数据的,数据会失去响应式。
const Test = useTestStore()
// 直接解构失去响应式
const { current, name } = Test
差异对比:
<template><div>响应式的值:{{ Test.current }}</div><div>解构出的非响应式值:{{ current }}--{{ name }}</div><button @click="change">change</button>
</template><script setup lang="ts">
import { useTestStore } from "./store";const Test = useTestStore();
const { current, name } = Test;
const change = () => {Test.current++;
};
</script><style lang="scss" scoped></style>
结果展示:

解决方案:
使用pinia的storeToRefs()方式将数据响应式化。如下:
// 引入
import { storeToRefs } from "pinia";
import { useTestStore } from "./store";const Test = useTestStore();
// 响应式化
const { current, name } = storeToRefs(Test);
const change = () => {Test.current++;
};
结果展示:

六、actions和getters
store/index.ts
import { defineStore } from "pinia";
import { Names } from "./store-name";type User = {name: string,age: number
}let result:User = {name: '小5',age: 18
}const Login = (): Promise<User> => {return new Promise((resolve) => {setTimeout(() => {resolve({name: "小4",age: 17})})})
}export const useTestStore = defineStore(Names.TEST, {state: () => {return {// 类型断言// <type>{} 通常用于类型断言,表示将某个值强制转换成指定的类型。user: <User>{},name: 'xiao5'}},// 类似于computed可以帮我们修饰我们的值getters: {newName(): string {return `$-${this.name}`}},// 可以操作异步 和 同步actions: {// 不能写箭头函数 否则this会指向错误// 同步setUser1() {this.user = resultthis.name = '小8'},// 异步async setUser2() {const result = await Login()this.user = resultthis.name = '小7'},}
})
App.vue
<template><div>actions:{{ Test.user }}</div><button @click="change1">同步</button><button @click="change2">异步</button><div>getters:{{ Test.newName }}</div>
</template><script setup lang="ts">
import { useTestStore } from "./store";const Test = useTestStore();
const change1 = () => {Test.setUser1();
};
const change2 = () => {Test.setUser2();
};
</script><style lang="scss" scoped></style>
结果展示:

另外,多个actions可以相互调用,多个getters也可以相互调用。
七、API
1.$reset
重置store到它的初识状态
import { useTestStore } from "./store";
const Test = useTestStore();
const reset = () => {Test.$reset();
};
2.$subscribe
用于订阅state的改变,只要有state的变化就会触发这个函数
$subscribe的第一个参数是个回调函数
Test.$subscribe((args, state) => {console.log("======>", args);console.log("======>", state);
});
返回值args主要包括effect、target、storeId等信息,state是state数据变化后的状态。如下图

第二个参数是是一个配置对象
Test.$subscribe((args, state) => {console.log("======>", args);console.log("======>", state);},{detached: true,deep: true,flush: "post",}
);
这三种配置详细如下:
detached(脱离状态):指组件从其父级组件或 DOM 树中被移除的状态。在这种状态下,组件不再接收更新,并且可以被销毁。Vue 2.x 中通过调用 $destroy() 方法来销毁组件,Vue 3.x 中则使用 teleport、keepAlive 等组合来控制组件的生命周期。
deep(深度监听):指对一个对象进行深度监听,在该对象的所有属性的值发生改变时,都能够得到通知。在 Vue.js 中,可以使用 vm.$watch() 方法来实现对数据的深度监听,Vue 3.x 中也提供了相应的 API 实现深度监听。
flush(刷新策略):指一种更新数据后如何刷新页面的策略。在 Vue.js 中,默认的刷新策略是异步批处理模式(nextTick 模式),即将所有数据的更新操作放入一个队列中,在下一个 tick 执行更新操作,以减少不必要的 DOM 操作和提高性能。除此之外,Vue.js 还支持同步刷新(sync)、立即刷新(pre)等刷新策略。
3.$onAction
用于订阅actions的调用,只要有actions被调用就会触发这个函数。
Test.$onAction((args) => {console.log(args);
});
返回值args主要包括after回调,args(actions传递的参数),name(触发的actions名字),onError(错误回调),store(store实例)等。如下图

八、pinia插件
pinia 和 vuex 都有一个通病 页面刷新状态会丢失
我们可以写一个pinia 插件缓存他的值
参考博客:满哥牛
相关文章:
Vue——状态管理库Pinia
写在前面:本文参考小满大牛的pinia专栏 一、Vuex与Pinia Vuex 和 Pinia 均是 Vue.js 的状态管理库,它们为 Vue 应用程序提供了一种集中式的、可预测的状态管理解决方案。 Vuex 是 Vue.js 官方推荐的状态管理库之一。它的核心概念包括 state、mutation…...
Linux:忘记root密码解决办法
如果你是虚拟机只要将光盘镜像连接到虚拟机上,以光盘iso镜像启动 如果你是真机或服务器那将实体u盘或实体光盘连接至设备并且以连接的设备启动 开机时候打断开机 使用 (u盘|光盘)引导启动 troubleshooting rescue a centos system 输入 1…...
Dockerfile(4) - RUN 指令详解
RUN 运行命令 shell 形式 命令在 shell 中运行Linux 上默认为 /bin/sh -cWindows 上 cmd /S /C RUN <command> exec 形式 RUN ["executable", "param1", "param2"] 必须双引号,不能是单引号 两种写法的实际栗子 RUN …...
一个完整的APP定制开发流程是怎样的?
随着移动互联网的发展,越来越多的 APP应用软件进入人们的生活,让我们的生活更便捷、更舒适。而随着互联网技术的进步,移动互联网应用软件开发行业也越来越成熟,为了适应市场需求,各种功能强大、性能良好的 APP应用软件…...
【数据结构】24王道考研笔记——线性表
线性表 目录 线性表定义和基本操作顺序表静态顺序表动态顺序表 链表单链表不带头结点:带头结点: 双链表循环链表循环单链表:循环双链表: 静态链表 顺序表链表比较逻辑结构:存储结构:基本操作: 定…...
【Linux C】基于树莓派/香橙派的蓝牙服务端——支持多蓝牙设备接入
一、需求 在树莓派/香橙派上利用开发板自带的蓝牙作为一个蓝牙服务端(主机),允许外来设备(从机)通过蓝牙接入进行通信,通信格式为透传方式;采用的编程语言为Linux C 二、环境准备 bluez安装 …...
鸿蒙App开发选择Java还是JavaScript?
众所周知, Java和 JavaScript是两种编程语言,这两种语言在不同的环境中都有许多用途。在鸿蒙 App开发中, Java和 JavaScript是两种常见的编程语言,它们都具有广泛的应用,并且都有其独特的优势。下面我们将就这两种编程…...
【Android】CountDownTimer的使用
android中怎么实现倒计时 在Android中,可以使用CountDownTimer类来实现倒计时。以下是一个简单的示例: javaCopy new CountDownTimer(30000, 1000) {public void onTick(long millisUntilFinished) {// 每次倒计时间隔1秒,更新UI上的倒计时剩…...
Linux :: 【基础指令篇 :: 文件及目录操作:(1)】:: ls :: 查看指定目录下的内容
前言:本篇是 Linux 基本操作篇章的内容! 笔者使用的环境是基于腾讯云服务器:CentOS 7.6 64bit。 学习集: C 入门到入土!!!学习合集Linux 从命令到网络再到内核!学习合集 目录索引&am…...
【商品详情 +关键词搜索】API 接口系列
首先,大家要到官方主页去申请一个 appkey,这个是做什么用的呢?App Key 是应用的唯一标识,TOP 通过 App Key 来鉴别应用的身份。AppSecret 是 TOP 给应用分配的密钥,开发者需要妥善保存这个密钥,这个密钥用来…...
RabbitMQ学习-发布确认高级
发布确认springboot版本 确认机制方案: 代码架构图: 配置文件: 在application.properties全局配置文件中添加spring.rabbitmq.publish-confirm-type属性,这个属性有以下几种值 none:禁用发布确认模式(默认)0 correlated:发布消…...
重载和内联函数
函数的默认参数 默认参数是指调用函数的时候,如果不写实参,那么将使用一个缺省值。 使用默认参数可以使你的函数更加灵活,同时减少了在不同上下文中为相同的参数重复编写相同的代码的需要。 return_type function_name(data_type paramete…...
从零学算法
198.你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额…...
《Linux0.11源码解读》理解(四) head之重新设置IDT/GDT
上节提到,现在cs:ip指向0地址,此处存储着作为操作系统核心代码的system模块,是由head.s和 main.c以及后面所有源代码文件编译链接而成。head.s(以下简称head)紧挨着main.c,我们先执行head。 重新设置内核栈 _pg_dir: _startup_3…...
<SQL>《SQL命令(含例句)精心整理版(4)》
《SQL命令(含例句)精心整理版(4)》 14 数据库对象14.1 表14.2 视图14.3 存储过程14.3.1 概念14.3.2 创建存储过程14.3.2 调用存储过程14.3.3 DbVisualizer工具中调用方法14.3.3 DB2命令行脚本调用方法14.3.4 DB2中两个存储过程报错…...
C++死锁
死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的状态称为死锁。 死锁通常发生…...
[自学记录02|百人计划]纹理压缩
一、什么是纹理压缩 纹理压缩是为了解决内存、带宽问题,专为在计算机图形渲染系统中存储纹理而使用的图像压缩技术。 1.图片格式和纹理格式的区别 (1)图片格式 图片格式是图片文件的存储格式,通常在磁盘、内存中储存和传输文件时使用;例如…...
C++泛型编程之模板
目录 一、什么是泛型编程 二、函数模板 2.1函数模板的概念 2.2函数模板格式 2.3函数模板的原理 2.5函数模板的实例化 2.6模板参数的匹配原则 三、类模板 3.1类模板的定义格式 3.2 类模板的实例化 四、非类型模板参数 五、模板的特化 5.1模板特化的概念:…...
极氪汽车 APP 系统云原生架构转型实践
作者:极氪汽车 前言 新能源汽车已经成为我国汽车市场再次崛起的关键支柱,随着新能源汽车市场的快速发展,不同类型的品牌造车厂商呈现出百花齐放的态势。极氪汽车是吉利控股集团旗下高端纯电汽车新品牌,2021 年 4 月极氪发布首款…...
一个UDP下载服务器的实现(模拟下载文件)
本期分享的主要是使用UDP实现文件下载功能,需要自己编写服务器和客户端,实现的功能主要有以下几个: (1)服务器可以为请求的用户下发文件数据(前提是服务器得有这个数据文件) (2&…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...
大模型真的像人一样“思考”和“理解”吗?
Yann LeCun 新研究的核心探讨:大语言模型(LLM)的“理解”和“思考”方式与人类认知的根本差异。 核心问题:大模型真的像人一样“思考”和“理解”吗? 人类的思考方式: 你的大脑是个超级整理师。面对海量信…...
运动控制--BLDC电机
一、电机的分类 按照供电电源 1.直流电机 1.1 有刷直流电机(BDC) 通过电刷与换向器实现电流方向切换,典型应用于电动工具、玩具等 1.2 无刷直流电机(BLDC) 电子换向替代机械电刷,具有高可靠性,常用于无人机、高端家电…...
CCF 开源发展委员会 “开源高校行“ 暨红山开源 + OpenAtom openKylin 高校行活动在西安四所高校成功举办
点击蓝字 关注我们 CCF Opensource Development Committee CCF开源高校行 暨红山开源 openKylin 高校行 西安站 5 月 26 日至 28 日,CCF 开源发展委员会 "开源高校行" 暨红山开源 OpenAtom openKylin 高校行活动在西安四所高校(西安交通大学…...
