Vue——状态管理库Pinia

news2024/11/24 4:45:03

写在前面:本文参考小满大牛的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 piniayarn 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: {

    },
    // 可以操作异步 和 同步 提交state
    actions: {

    }
})

简单的使用仓库的数据
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要通过commitdispatch方法调用仓库修改。

<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: {

    },
    // 可以操作异步 和 同步 提交state
    actions: {
        // 不能写箭头函数 否则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 = result
            this.name = '小8'
        },
        // 异步
        async setUser2() {
            const result = await Login()
            this.user = result
            this.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主要包括effecttargetstoreId等信息,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 插件缓存他的值
参考博客:满哥牛

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/565172.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++初阶】类与对象(中)之取地址及const取地址操作符重载

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

架构整洁之道中篇(组件构建原则软件架构)

目录 1.组件构建原则 1.1.组件 1.2.组件聚合 1.3.组件耦合 2.软件架构 2.1.什么是软件架构&#xff1f; 2.2.独立性 2.3.划分边界 2.4.策略与层次 2.5.业务逻辑 2.6.尖叫的软件架构 2.7.整洁架构 2.8.层次与边界 2.9.Main组件 2.10.测试边界 2.11.整洁的嵌入式…

Edgedetect2

边缘检测&#xff0c;检查数据变化&#xff0c;用异或实现 对于 8 位矢量中的每个位&#xff0c;检测输入信号何时从一个时钟周期变为下一个时钟周期&#xff08;检测任何边沿&#xff09;。输出位应在发生 0 到 1 转换后设置周期。 以下是一些示例。为清楚起见&#xff0c;in…

HNU-电路与电子学-小班4

第四次小班讨论 一、题目 1、书 3-41、3-62 2、书 4-23、4-26 3、设计一个时序电路。该电路仅在连续三个或三个以上时钟期间&#xff0c;且两个输入信号 X1 和 X2 相同时&#xff0c;输出信号 Z 为 1&#xff0c;其余情况 Z 为 0。试做出该电路的 Mealy 机和 Moore 机状态…

Windows:设置右键用RStudio打开文件和文件夹

0. 前言 在使用RStudio写R脚本的时候总是要先打开它&#xff0c;再通过它打开脚本和文件夹&#xff0c;感觉不是很方便。由于VSCode以及其他软件都可以整合到右键菜单中打开文件或文件夹&#xff0c;因此就折腾了一下怎么在右键中使用RStudio打开文件&#xff0c;下面是效果展…

简析java JNI技术

前言 认识JNI(Java Native Interface)技术&#xff0c;了解Java调用本地C/C库的简单原理以及一些基本的知识点&#xff1b;自己编写一个自定义的JNI接口。 一、简介 JNI是Java Native Interface的缩写&#xff0c;通过使用 Java本地接口书写程序&#xff0c;可以确保代…

在vue3中如何使用百度地图API(详细步骤+demo示例)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、注册账号、申请成为开发者二、申请密钥AK三、在vue3.0中使用百度地图API 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、注册账号…

htb Mailroom里容器(Debian 11)图形界面显示在本机kali上,socat,unix转发,容器里不安装xrdp

在攻击机kali(ip:10.10.14.18)上运行chisel服务端: chisel server -v -p 60080 --socks5 在靶机的虚拟机(ssh root10.10.11.209)上,执行docker exec containers_sites_1 /bin/bash,进入容器里 进入容器后,先下载kali上的socat和chisel: curl -o /bin/chisel http://10.10.14…

使用JMeter+Grafana+Influxdb搭建可视化性能测试监控平台

【背景说明】 使用jmeter进行性能测试时&#xff0c;工具自带的查看结果方式往往不够直观和明了&#xff0c;所以我们需要搭建一个可视化监控平台来完成结果监控&#xff0c;这里我们采用三种JMeterGrafanaInfluxdb的方法来完成平台搭建 【实现原理】 通过influxdb数据库存储…

初学用于华为鸿蒙系统(HarmonyOS)的编程开发工具HUAWEI DevEco Studio:你好,鴻蒙~

本文是6月6日博文“初学用于华为鸿蒙系统(HarmonyOS)的编程开发工具HUAWEI DevEco Studio”的续篇。 成功通过华为开发者联盟的实名认证审核后&#xff0c;使用远程模拟器(Remote Emulator)运行程序。 步骤如下&#xff1a; 菜单Tools - Device Manager&#xff1a; 点击设备…

Vue列表渲染

1&#xff0c;回顾HTML列表&#xff1f; 答&#xff1a;列表分为顺序列表ol&#xff0c;无序列表ul&#xff0c;用于在网页上以表格的形式进行数据展示&#xff0c;数据放在单元格之中&#xff0c;可以用于布局或者展示某个具体对象的信息。li表示列表的每一项。自定义列表为dl…

C++多态详解(虚函数重写、接口继承、虚函数表详解)

目录 1. 多态概念 2. 多态的定义及实现 2.1 多态的构成条件 2.2 虚函数重写 2.3 C11 override和final 2.4 重载、覆盖&#xff08;重写&#xff09;、隐藏&#xff08;重定义&#xff09;的对比 3. 抽象类 3.1 概念 3.2 接口继承和实现继承 4. 多态的原理 4.1 虚函数表 4.2…

ESP32设备驱动-VCNL4010光传感器驱动

VCNL4010光传感器驱动 文章目录 VCNL4010光传感器驱动1、VCNL4010介绍2、硬件准备3、软件准备4、驱动实现1、VCNL4010介绍 VCNL4010 专为更短的距离而设计,不超过 200 毫米(约 7.5" ) 并且根据我们的实验,我们发现它在大约 10-150 毫米的距离内效果最佳。这对于检测手…

水表远程监控系统有什么功能吗?

水表远程监控系统是通过远程传输水表数据&#xff0c;实现对水表的远程监控和管理的一种智能化系统。它主要具备以下功能&#xff1a; 1.远程抄表功能&#xff1a;通过远程传输技术&#xff0c;实现对水表的远程抄表和监控&#xff0c;无需人工上门抄表&#xff0c;节省人力成本…

ChatGPT超详细教程-提问、使用、技巧~

huChatGPT已经面世很长时间了&#xff0c;很多人已经开始依赖ChatGPT了&#xff0c;逐渐应用到自己的生活工作学习中去了&#xff0c;然而还有很多人嚷嚷着不好用&#xff0c;真的不好用的话为什么广受好评&#xff0c;还有很多人一直在用&#xff1f; 当然也有可能真的对你没…

uni-app基础

1、基本语言和开发规范 uni-app代码编写&#xff0c;基本语言包括js、vue、css。以及ts、scss等css预编译器。 在app端&#xff0c;还支持原生渲染的nvue&#xff0c;以及可以编译为kotlin和swift的uts。 但是&#xff0c;DCloud提供了使用js编写服务器代码的uniCloud云引擎…

Unity Lighting Mode

在Light中Mode设置为Mixed时&#xff0c;Lighting Mode&#xff08;在Window->Rendering->Light->Scene&#xff09;有三种选项如下图&#xff1a; Baked Indirect 烘焙间接光,效果最好性能最耗 混合光源照亮的动态游戏对象将接收&#xff1a; 实时直接光照。烘焙间接…

【iOS_锁】

文章目录 前言锁线程安全锁&#x1f512;的作用锁的种类互斥锁 自旋锁加锁原理缺点对比自旋锁的缺点互斥锁的缺点 各种锁OSSpinLock使用OSSpinLockOSSpinLock存在缺陷 互斥锁分为两种&#xff1a; 递归锁、非递归锁 os_unfair_lock 【非递归互斥锁】锁的修饰使用 自旋锁的优先级…

数据结构初阶——堆排序

思维导图&#xff1a; 目录 一&#xff0c;堆排序的概念 二&#xff0c;堆排序的实现 2.1将数组变成堆 2.2堆有序化 二,全部代码 一&#xff0c;堆排序的概念 百度百科的解释如下&#xff1a;堆排序&#xff08;英语:Heapsort&#xff09;是指利用堆这种数据结构所设计…

Python——第7章 pandas数据分析实战

7.1pandas常用数据类型 7.1.1一维数组与常用操作 import pandas as pd import matplotlib.pyplot as plt#设置输出结果对齐方式 pd.set_option(display.unicode.ambiguous_as_wide,True) pd.set_option(display.unicode.east_asian_width,True)#自动创建从0开始的非负整数索引…