实现简易 Pinia 核心机制

题目描述

实现一个简单的 defineStore 函数。

counter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { ref, computed } from "vue";

/**
* 类 Pinia defineStore 函数
* @param {Function} fn 仓库函数
*/
function defineStore(fn) {}

export const useCounterStore = defineStore(() => {
const count = ref(0);
function increment() {
count.value++;
}

return { count, increment };
});

实现思路

  1. 基础功能实现
    根据 Pinia 中 defineStore 的用法,该函数应返回一个可调用函数(如 useCounterStore),该函数执行时会返回仓库函数的调用结果。基础实现如下:
counter.js
1
2
3
4
5
6
7
8
9
/**
* 类 Pinia defineStore 函数
* @param {Function} fn 仓库函数
*/
function defineStore(fn) {
return () => {
return fn();
};
}
  1. 状态单例化
    基础实现存在明显问题:每次调用都会创建新的状态对象,不符合全局状态管理需求。我们通过闭包缓存状态,确保多次调用返回同一实例:
counter.js
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 类 Pinia defineStore 函数
* @param {Function} fn 仓库函数
*/
function defineStore(fn) {
let state;
return () => {
if (state) return state;
state = fn(); // 使用闭包缓存调用结果
return state;
};
}
  1. 副作用管理(进阶)
    Vue 的响应式系统(如 computed/watch)会产生副作用。使用 effectScope 可统一管理这些副作用,便于后续清理。
counter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { effectScope } from "vue";

/**
* 类 Pinia defineStore 函数
* @param {Function} fn 仓库函数
*/
function defineStore(fn) {
let state;
return () => {
if (state) return state;
// 创建新的 effect 作用域
const scope = effectScope(true);
state = scope.run(fn); // 在作用域中运行工厂函数
return state;
};
}