核心架构总览
src/
├── store.ts # Store 核心实现
├── rootStore.ts # 根 Store 管理
├── pinia.ts # 主入口和核心 API
├── hmr.ts # 热模块替换支持
├── types.ts # 类型定义
├── deprecations.ts # 废弃 API
└── devtools.ts # Devtools 集成
核心源码解析
创建 Pinia 实例
// src/pinia.ts
export function createPinia(): Pinia {
// 创建一个 effect 作用域,用于管理所有 store 的响应式效果
const scope = effectScope(true);
// 在作用域内创建全局状态树
const state = scope.run(() => ref<Record<string, StateTree>>({}))!;
// 创建 pinia 实例,markRaw 标记避免被响应式处理
const pinia: Pinia = markRaw({
// Vue 插件安装方法
install(app: App) {
// 设置当前活跃的 pinia 实例
setActivePinia(pinia);
// 提供依赖注入
app.provide(piniaSymbol, pinia);
// 全局挂载
app.config.globalProperties.$pinia = pinia;
},
// 内部属性:
_p: [], // 插件列表
_a: null, // 当前 app 实例
_e: scope, // effect 作用域
_s: new Map(), // store 的映射表
state, // 全局状态树
});
return pinia;
}
定义 Store 的核心函数
// src/store.ts
export function defineStore(idOrOptions: string | DefineStoreOptions, setup?: () => {}, setupOptions?: DefineSetupStoreOptions): StoreDefinition {
let id: string;
let options: DefineStoreOptions | DefineSetupStoreOptions;
// 参数重载处理
if (typeof idOrOptions === "string") {
id = idOrOptions;
options = setupOptions || {};
if (typeof setup !== "function") {
options = setup || {};
}
} else {
options = idOrOptions;
id = idOrOptions.id;
}
function useStore(pinia?: Pinia | null, hot?: StoreGeneric): StoreGeneric {
// 获取当前 Vue 实例(如果在组件内调用)
const currentInstance = getCurrentInstance();
// 获取 pinia 实例(优先使用参数传入的,其次从组件注入获取)
pinia = pinia || (currentInstance && inject(piniaSymbol));
if (pinia) setActivePinia(pinia);
// 确保有活跃的 pinia 实例
pinia = activePinia!;
// 如果该 store 尚未创建
if (!pinia._s.has(id)) {
// 区分 options 和 setup 两种定义方式
if (typeof setup === "function") {
createSetupStore(id, setup, options, pinia);
} else {
createOptionsStore(id, options as DefineStoreOptions, pinia);
}
}
// 获取 store 实例
const store: Store = pinia._s.get(id)!;
// 处理热更新
if (hot) {
// ...热更新逻辑
}
// SSR 处理
if (__SSR__ && currentInstance && currentInstance.proxy) {
// ...SSR 逻辑
}
return store as any;
}
useStore.$id = id;
return useStore;
}
创建 Composition API 风格的 Store
// src/store.ts
function createSetupStore(id: string, setup: () => {}, options: DefineSetupStoreOptions, pinia: Pinia): Store {
let scope!: EffectScope;
// 创建部分 store 定义
const partialStore = {
_p: pinia, // 所属的 pinia 实例
$id: id, // store 的唯一 ID
$onAction: addSubscription.bind(null, actionSubscriptions),
$patch,
$reset,
$subscribe(callback, options = {}) {
// ...订阅逻辑
},
$dispose,
} as unknown as Store;
// 创建响应式 store
const store: Store = reactive(partialStore) as Store;
// 将 store 注册到 pinia 中
pinia._s.set(id, store);
// 在 effect 作用域中运行 setup 函数
const setupStore = pinia._e.run(() => {
scope = effectScope();
return scope.run(() => setup());
})!;
// 遍历 setup 返回的结果
for (const key in setupStore) {
const prop = setupStore[key];
// 处理 ref 和 reactive
if (isRef(prop) && !isComputed(prop)) {
// 如果是 ref(非 computed),将其加入 state
if (!pinia.state.value[id]) {
pinia.state.value[id] = {};
}
pinia.state.value[id][key] = prop;
} else if (typeof prop === "function") {
// 处理 action 方法
const actionValue = wrapAction(key, prop);
setupStore[key] = actionValue;
}
}
// 合并 setup 返回的结果到 store
Object.assign(store, setupStore);
// 允许插件扩展 store
pinia._p.forEach((extender) => {
Object.assign(store, extender({ store, app: pinia._a, pinia }));
});
return store;
}
Action 包装器
// src/store.ts
function wrapAction(name: string, action: Function) {
return function (this: any) {
// 设置当前活跃的 pinia 实例
setActivePinia(pinia);
const args = Array.from(arguments);
// 回调队列
const afterCallbackList: Array<Function> = [];
const onErrorCallbackList: Array<Function> = [];
// 定义 after 和 onError 钩子
function after(callback: Function) {
afterCallbackList.push(callback);
}
function onError(callback: Function) {
onErrorCallbackList.push(callback);
}
try {
// 执行 action,确保正确的 this 上下文
const ret = action.apply(this && this.$id === id ? this : store, args);
// 处理异步 action
if (ret instanceof Promise) {
return ret
.then((value) => {
// 执行成功回调
afterCallbackList.forEach((callback) => callback(value));
return value;
})
.catch((error) => {
// 执行错误回调
onErrorCallbackList.forEach((callback) => callback(error));
return Promise.reject(error);
});
}
// 同步 action 的成功回调
afterCallbackList.forEach((callback) => callback(ret));
return ret;
} catch (error) {
// 同步 action 的错误处理
onErrorCallbackList.forEach((callback) => callback(error));
throw error;
}
};
}
关键设计解析
响应式状态管理
Pinia 使用 Vue 的 reactive 系统管理状态:
// 在 createSetupStore 中
if (isRef(prop) && !isComputed(prop)) {
if (!pinia.state.value[id]) {
pinia.state.value[id] = reactive({});
}
pinia.state.value[id][key] = prop;
}
依赖注入系统
通过 Vue 的 provide/inject 实现 store 的共享:
// 安装时提供 pinia 实例
app.provide(piniaSymbol, pinia);
// 使用时注入
pinia = inject(piniaSymbol);
类型系统实现
Pinia 的类型系统是其一大亮点,通过复杂的泛型实现完善的类型推断:
// src/types.ts
export interface StoreDefinition<
Id extends string = string,
S extends StateTree = StateTree,
G extends _GettersTree<S> = _GettersTree<S>,
A = _ActionsTree
> {
(pinia?: Pinia | null, hot?: StoreGeneric): Store<Id, S, G, A>
$id: Id
}
性能优化策略
-
惰性初始化:Store 只有在第一次使用时才会被创建;
-
Effect Scope:使用 Vue 3 的 effectScope 管理响应式效果,便于统一清理;
-
标记非响应式:对 pinia 实例使用 markRaw 避免不必要的响应式转换;
-
缓存策略:Store 实例会被缓存,避免重复创建;
import.meta.glob 动态加载
上一篇