Vue3状态管理之Pinia的入门使用教程

作者:而又何羡乎 时间:2024-05-09 15:12:03 

Vue3 新的发展方向(来源于尤大知乎)

Vue 3 将在 2022 年 2 月 7 日 成为新的默认版本

基于 Vite 的极速构建工具链

<script setup> 带来的开发体验更丝滑的组合式 API 语法

Volar 提供的单文件组件 TypeScript IDE 支持

vue-tsc 提供的针对单文件组件的命令行类型检查和生成

Pinia 提供的更简洁的状态管理

新的开发者工具扩展,同时支持 Vue 2/Vue 3,并且提供一个插件系统来允许社区库自行扩展开发者工具面板。

一、Pinia 简介与基础

1.1 Pinia 简介

  • 官方地址:https://pinia.vuejs.org/

  • Pinia 是 Vuex4 的升级版,也就是 Vuex5

  • Pinia 极大的简化了Vuex的使用,是 Vue3的新的状态管理工具

  • Pinia 对 ts的支持更好,性能更优, 体积更小,无 mutations,可用于 Vue2 和 Vue3

  • Pinia支持Vue Devtools、 模块热更新和服务端渲染

1.2 Pinia 基础

&emsp;&emsp;Vuex 与 Pinia 对比

  • Vuex 中核心部分: State、Getters、Mutations(同步) 和 Actions(异步)

  • Pinia 中核心部分: State、Getters 和 Actions(同步异步均支持)

&emsp;&emsp;Pinia 各部分作用

  • State: 类似于组件中data,用于存储全局状态

  • Getters: 类似于组件中的computed,根据已有的State封装派生数据,也具有缓存的特性

  • Actions: 类似于组件中的methods,用于封装业务逻辑,同步异步均可以

&emsp;&emsp;Pinia 官方示例JS版本

import { defineStore } from 'pinia'

export const todos = defineStore('todos', {
 state: () => ({
   /** @type {{ text: string, id: number, isFinished: boolean }[]} */
   todos: [],
   /** @type {'all' | 'finished' | 'unfinished'} */
   filter: 'all',
   // type will be automatically inferred to number
   nextId: 0,
 }),
 getters: {
   finishedTodos(state) {
     // autocompletion! ?
     return state.todos.filter((todo) => todo.isFinished)
   },
   unfinishedTodos(state) {
     return state.todos.filter((todo) => !todo.isFinished)
   },
   /**
    * @returns {{ text: string, id: number, isFinished: boolean }[]}
    */
   filteredTodos(state) {
     if (this.filter === 'finished') {
       // call other getters with autocompletion ?
       return this.finishedTodos
     } else if (this.filter === 'unfinished') {
       return this.unfinishedTodos
     }
     return this.todos
   },
 },
 actions: {
   // any amount of arguments, return a promise or not
   addTodo(text) {
     // you can directly mutate the stat 00e
     this.todos.push({ text, id: this.nextId++, isFinished: false })
   },
 },
})

二、Pinia 在Vue3-Vite中的使用

2.1 基础使用流程

① 创建一个vue vite项目

PS C:\Users\FORGET\Desktop\vue-pinia-demo> npm init vite@latest
Need to install the following packages:
 create-vite@latest
Ok to proceed? (y) y
√ Project name: ... pinia-demo
√ Select a framework: ? vue
√ Select a variant: ? vue-ts

Scaffolding project in C:\Users\FORGET\Desktop\vue-pinia-demo\pinia-demo...

Done. Now run:

cd pinia-demo
 npm install
 npm run dev
PS C:\Users\FORGET\Desktop\vue-pinia-demo> cd .\pinia-demo\
PS C:\Users\FORGET\Desktop\vue-pinia-demo\pinia-demo> npm install

② 安装 pinia,-S是为了将其保存至package.json中,便于Git管理给其他人的使用

PS C:\Users\FORGET\Desktop\vue-pinia-demo\pinia-demo> npm install pinia -S

# package.json文件中
"dependencies": {
   "pinia": "^2.0.9",
   "vue": "^3.2.25"
 },

③ 创建 pinia 实例并挂载到 vue中

// main.ts 文件
import { createApp } from 'vue'
import App from './App.vue'
import {createPinia} from 'pinia'
// 创建 Pinia 实例
const pinia = createPinia()
// 创建 Vue 实例
const app = createApp(App)
// 挂载到 Vue 根实例
app.use(pinia)
app.mount('#app')

④ 在src文件下创建一个store文件夹,并添加index.ts

// store/index.ts
import { defineStore } from 'pinia'
// 1. 定义容器、导出容器
// 参数1:容器的ID,必须是唯一的,后面Pinia会把所有的容器挂载到根容器
// 参数2:一些选项对象,也就是state、getter和action
// 返回值:一个函数,调用即可得到容器实例

export const useMainStore =  defineStore('main',{
   // 类似于Vue2组件中的data,用于存储全局状态数据,但有两个要求
   // 1. 必须是函数,目的是为了在服务端渲染的时候避免交叉请求导致的数据状态污染
   // 2. 必须是箭头函数,这样是为了更好的 TS 类型推导
   state:()=>{
       return {
           info:"pinia 可以使用"
       }
   },
   getters:{},
   actions:{}
})

// 2. 使用容器中的 state
// 3. 通过 getter 修改 state
// 4. 使用容器中的 action 同步和异步请求

⑤ 在组件中使用

<template>
 <h1>{{ mainStore.info}}</h1>
</template>

<script lang="ts" setup>
import { useMainStore } from "../store";
const mainStore = useMainStore();
</script>

<style>
</style>

2.2 state 中数据的解构访问

状态管理中

// store/index.ts
state:()=>{
       return {
           info:"pinia 可以使用",
           count:10
       }
   },

组件中

<template>
 <h1>{{ mainStore.count }}</h1>
 <h1>{{ mainStore.info }}</h1>
 <hr />
 <h1>{{ count }}</h1>
 <h1>{{ info }}</h1>
 <p>
   <button @click="alertData">修改数据</button>
 </p>
</template>

<script lang="ts" setup>
import { toRefs } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore } from "../store";
const mainStore = useMainStore();
// 解构数据,但是得到的数据是不具有响应式的,只是一次性的
// 相当于仅仅只是...mainStore而已,只是做了reactive处理,并没有做toRefs
// const { count, info } = useMainStore();
// 解决方法:
// 1. 通过使用toRefs函数,因为前面所说相当于是通过reactive处理,因此可以
// const { count, info } = toRefs(mainStore);
// 2. 通过pinia中提供的storeToRefs方法来解决,推荐使用
const { count, info } = storeToRefs(mainStore);
const alertData = () => {
 mainStore.count += 10
}
</script>

<style>
</style>

2.3 state 中数据的修改方式(actions和组件中)

一般的修改

const alertData = () => {
 // 方式一:最简单的方法,如下
 // 解构后更改方式
 // count.value += 10
 // 结构前更改方式
 // mainStore.count += 10
 // 方式二:若要同时修改多个数据,建议使用$patch来实现批量更新,在内部做了优化
 // mainStore.$patch({
 //   count: mainStore.count + 1,
 //   info: "hello"
 // })
 // 方式三:更好的批量更新方法,通过$patch传递一个函数来实现,这里的state就是useMainStore容器中的state
 mainStore.$patch(state => {
   state.count += 10
   state.info = "pinia批量更新"
 })
}

通过actions修改

// store/index.ts
// 类似于vue2组件的methods,用于封装业务逻辑,修改state
// // 注意:不能使用箭头函数来定义actions,因为箭头函数绑定外部的this
   actions:{
       changeState (){
           this.count += 10
           this.info = "actions修改数据"
       },
       changeStates (num:number){
           this.count += num + 2
           this.info = "actions修改数据"
       }
   }
const alertData = () => {
 // 方式一:最简单的方法,如下
 // 解构后更改方式
 // count.value += 10
 // 结构前更改方式
 // mainStore.count += 10
 // 方式二:若要同时修改多个数据,建议使用$patch来实现批量更新,在内部做了优化
 // mainStore.$patch({
 //   count: mainStore.count + 1,
 //   info: "hello"
 // })
 // 方式三:更好的批量更新方法,通过$patch传递一个函数来实现,这里的state就是useMainStore容器中的state
 // mainStore.$patch(state => {
 //   state.count += 10
 //   state.info = "pinia批量更新"
 // })
 // 方式四:通过 actions 来修改数据
 mainStore.changeState()
 mainStore.changeStates(10)
}

2.4 getters 的使用

定义

// 类似于组件的computed,用来封装计算属性,具有缓存的功能
   getters:{
    // 函数接收一个可选参数:state状态对象
       count10(state){
           return state.count += 10
       },
       count10(state){
           return this.count += 10
       },
       // 若使用this.count,则必须指明返回数据的类型
       count11():number{
           return this.count += 11
       }
   },

使用

<h1>{{ mainStore.count10 }}</h1>

三、Pinia 数据持久化

保存至localStorage中

import { defineStore } from 'pinia';
const useLoginStore = defineStore({
 id: 'login',
 //   state: () => ({
 //     num: 1,
 //   }),
 state: () => ({
   info: 'pinia 可以使用',
 }),
 getters: {},
 actions: {
   alertInfo() {
     this.info = '可以可以,这个秒';
   },
 },
});

// 数据持久化
// 1. 保存数据
const instance = useLoginStore();
instance.$subscribe((_, state) => {
 localStorage.setItem('login-store', JSON.stringify({ ...state }));
});
// 2. 获取保存的数据,先判断有无,无则用先前的
const old = localStorage.getItem('login-store');
if (old) {
 instance.$state = JSON.parse(old);
}
export default useLoginStore;

使用 插件 pinia-plugin-persist 可以辅助实现数据持久化功能

# 安装插件
pnpm install pinia-plugin-persist --save
// main.ts文件中
import { createPinia } from 'pinia';
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import piniaPluginPersist from 'pinia-plugin-persist';
const pinia = createPinia();
pinia.use(piniaPluginPersist);
const app = createApp(App);
app.use(router);
app.use(pinia);
app.mount('#app');

// 接着在对应的 store 里开启 persist 即可。数据默认存在 sessionStorage 里,并且会以 store 的 id 作为 key。
import { defineStore } from 'pinia';
import piniaPluginPersist from 'pinia-plugin-persist';
const useLoginStore = defineStore({
 id: 'login',
 //   state: () => ({
 //     num: 1,
 //   }),
 state: () => ({
   info: 'pinia 可以使用',
 }),
 // 开启数据缓存
 persist: {
   enabled: true,
 },
 getters: {},
 actions: {
   alertInfo() {
     this.info = '可以可以,这个秒';
   },
 },
});
export default useLoginStore;

其它设置,自定义保存名称,保存位置和需要保存的数据

// 开启数据缓存
 persist: {
   enabled: true,
   strategies: [
     {
       // 自定义名称
       key: 'login_store',
       // 保存位置,默认保存在sessionStorage
       storage: localStorage,
       // 指定要持久化的数据,默认所有 state 都会进行缓存,你可以通过 paths 指定要持久化的字段,其他的则不会进行持久化。
       paths: ['age'],
     },
   ],
 },

来源:https://blog.csdn.net/qq_44285092/article/details/122627683

标签:vue3,状态管理,pinia
0
投稿

猜你喜欢

  • python区块链简易版交易实现示例

    2023-09-28 15:20:10
  • python中序列的逆序方式

    2023-12-12 19:49:07
  • 如何通过PHP实现Des加密算法代码实例

    2023-10-08 09:41:55
  • jQuery 1.4官方中文手册[译]

    2010-01-20 10:46:00
  • 介绍Python的Django框架中的QuerySets

    2021-04-19 18:58:32
  • python-for x in range的用法(注意要点、细节)

    2022-11-12 22:40:49
  • MySql COALESCE函数使用方法代码案例

    2024-01-14 03:47:25
  • Python深度学习之使用Albumentations对图像做增强

    2023-11-24 06:18:23
  • Python获取文件所在目录和文件名的方法

    2021-04-07 05:44:35
  • Go本地测试小技巧解耦任务拆解

    2023-08-29 14:09:26
  • python函数缺省值与引用学习笔记分享

    2023-10-22 19:43:20
  • python tqdm库的使用

    2023-10-30 22:32:44
  • JS实现页面打印(整体、局部)

    2024-04-26 17:14:27
  • asp动态页面防采集的新方法

    2011-02-26 10:44:00
  • Ubuntu12下编译安装PHP5.3开发环境

    2023-11-15 14:36:29
  • Python下载ts文件视频且合并的操作方法

    2021-11-15 15:40:19
  • mysql 队列 实现并发读

    2024-01-14 21:16:26
  • Selenium 安装和简单使用的实现

    2023-12-01 07:22:55
  • Python实现12306火车票抢票系统

    2023-09-30 01:33:31
  • python实战串口助手_解决8串口多个发送的问题

    2021-12-07 09:53:51
  • asp之家 网络编程 m.aspxhome.com