跳到主要内容

认识

2024年03月18日
柏拉文
越努力,越幸运

一、认识


Pinia 主要通过两个 API 来实现高效、灵活的状态管理解决方案。

  1. createPinia: 基于 effectScope 创建一个 effect 作用域, 并传入 ture, 阻断和父级的联系。独立收集收集和管理副作用。使用 ref 创建一个响应式对象 state, 这是 Pinia store 的状态对象。通过 scope.run() 将其运行在之前创建的效果作用域中,意味着 state 的所有响应式变更都将被该作用域管理。基于 markRaw 创建并标记一个 Pinia 对象, 避免其状态管理逻辑被 Vue 追踪。Pinia 对象中有一个 install 方法、_a_e_s 属性。作用如下:

    • instanll: Pinia 暴露给 Vue 应用的接口,用于安装 Pinia 插件。内部会为 Pinia 建立一个 Symbol 唯一标识, 基于 app.provide 注入到根组件实例中。

    • _a: 存储 Vue 应用实例,通常用于内部访问 Vue 应用上下文

    • _e: 存储之前创建的效果作用域

    • _s: 一个存储所有 store 实例的映射,用于管理和访问应用中的所有状态存储

  2. defineStore: 以独一无二的 storeId 基于传入的对象或者函数创建 store。 内部会定义一个 useStore 函数, 函数内部首先通过 getCurrentInstance 获取当前组件实例, 通过 inject 获取之前注入的 Pinia 对象。判断 Pinia._s 中是否存在传入的 storeId 对象, 如果存在, 直接返回 storeId 对应的 store, 如果不存在, 创建 storeId 对应的 store,传入对象、或者函数会走不同的逻辑来创建。其中, 函数的创建逻辑为: 创建一个响应式对象 store, 因为每一个 storeId 对应着自己的 store。在 pinia._e 父级作用域中, 创建一个子作用域, 在子作用域中运行传入的函数, storeId 对应的 store 函数产生的副作用由子作用域来管理。得到了一个作用域中产生的 store。对这个 store 中的函数进行包装, 主要是将 this 指向改变为当前的 store。最后合并 store 与作用域中产生的 store, 并更新 pinia._s

二、工作流


Pinia 基于 Vue.js 3.0 提供的 effectScope 实现新的状态管理方式。实现如下:

1. 定义 defineStore, 基于 effectScope 创建一个 effect 作用域, 在这个作用域中管理传入的 store

import { effectScope } from "vue";

function defineStore(setup){
let state;
let isChange = false;
const scope = effectScope(true);
return ()=>{
if(!isChange){
state = scope.run(setup);
isChange = true;
}
return state;
}
}

export default defineStore;

2. 定义 useStore, 基于 defineStore, 传入一个回调函数, 回调函数内部就是我们的 store

import { computed, ref } from "vue";
import defineGlobalStore from "./defineStore";

const useStore = defineGlobalStore(() => {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
const updateCount = () => {
count.value++;
};
return { count, doubleCount, updateCount };
});

export default useStore;

3. 随后, 我们就可以在不同的组件中使用 useStore 来进行子父组件、兄弟组件、全局通信