pinia的使用与过程分析
前言
pinia
作为全局的状态管理器,可帮助我们在vue
项目中跨多个组件间进行通讯,支持vue2
以及vue3
,我们可通过操作state、action,就像是在一SFC文件中使用一般,
本文将从pinia
的使用,到源码层面来分析关于pinia
的工作过程,加深对pinia
的理解,以及在pinia
的实现过程上学习到了什么等等!!
pinia的使用
- 首先在应用程序入口中将pinia引入到vue项目中
1
2
3
4
5
6
7
8
9import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app') - 根据业务场景,定义自己的模块store
1
2
3
4
5
6
7
8
9
10
11
12
13
14// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0 }
},
// 也可以这样定义
// state: () => ({ count: 0 })
actions: {
increment() {
this.count++
},
},
}) - 直接在组件中使用这样子之后,我们就可以在
1
2
3
4
5
6
7
8
9
10
11
12
13<template>
<!-- 直接从 store 中访问 state -->
<div>Current Count: {{ counter.count }}</div>
</template>
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
counter.count++
// 自动补全! ✨
counter.$patch({ count: counter.count + 1 })
// 或使用 action 代替
counter.increment()
</script>vue
上下文中直接使用store.state
以及store.actions
了!
😕 那么,这个pinia
在执行的过程中,发生了什么呢?为什么能够像在SFC文件中简单使用,就能够实现跨组件级别的共享呢?下面将一一道来!
pinia使用过程分析
使用createPinia()创建一vue插件,池子的形成
一切从方法源头开始:const pinia = createPinia()
,通过这个createPinia()
方法,创建一个pinia插件
,该插件Pinia
对象的组成结构如下:
1 | // rootStore.ts |
⭐ 通过对这个Pinia
对象的结构进行分析,我们可以得知,在应用程序入口这里所创建出来的pinia,仅仅只是一个“池子”的概念,也就是将store
容器给创建好,将全局的state
状态树给维护好,等待后续的使用,这个过程如下所示:
1 | export const piniaSymbol = ( |
:+1: 从上述代码这里我们看出,将在全局范围内注入一个pinia
对象,也就是说,我们可以在vue上下文中通过enject
的方式来获取,因为这里将对依赖的访问通过一个公共的piniaSymbol
来进行访问了,因此,我们也有理由相信,当使用的useStore()
的方式来创建/获取到一个store对象的时候,也是通过这个方式来获取的!
根据所需创建子store,丰富池子内容
👉 借助于defineStore()
创建一个store对象,也就是创建一个useStore()函数
,这里是一个高阶函数,返回一个函数的函数,因此,当我们通过defineStore()
来定义一个store对象的时候,其实就是创建了一个store函数的时候,这里仅仅是捆绑id并创建了一个store函数,还并没有真正调用到这个store函数, 👉 当调用了const counter = useCounterStore()
的时候,才是真正执行了这个store函数!
1 | export function defineStore(id){ |
🌟 上述在创建store的时候,会将其他相关的api一同集成到store对象中,切将store给reactive化
1 | const partialStore = { |
⭐ 上述关于store的创建,也同时说明了关于其他成员属性的由来,以及各自都是用来做什么操作的!
🌠 这样子之后,我们便能够在后续的操作中,通过提供的id来从pinia._s
中获取到已经初始化完成的store
对象!
👉 每一个store的创建过程其实就是将state
、getters
、actions
给“脱壳响应化”后,追加上公共的属性/API的过程!!
学到点什么
- 在基于整套框架层面进行的编码时,可以借鉴这个
pinia
实现provide
以及enject
的方式,如果我们需要在整个app层面,提供能够在各个组件直接访问的资源时,可通过自定义统一的symbol()属性的方式,让所有的访问者都通过一个唯一的标识来获取! - 在定义vue插件的时候,可采用懒加载的方式,先提供一个容器,容器的外观可以先定义出来,然后在实际需要使用到的时候,才进行初始化并进行存储操作!
- 使用选项式的方式与组合式的方式来使用
pinia
,其结果都是一样的,无非就是使用了选项式的时候,需要经过程序自动转换的一个过程!