Pinia 核心源码深度解析
一、核心模块与功能概览
Pinia 的 Store 核心实现模块,主要包含以下功能:
- Store 创建:处理 Options API 和 Setup API 两种定义方式
- 响应式状态管理:深度合并状态、处理 Ref/Reactive 对象
- Action 与 Getter 处理:实现 action 上下文绑定和 getter 缓存
- 插件系统:支持通过
pinia.use()扩展功能 - 热更新(HMR) :支持开发环境下的模块热替换
- 副作用管理:通过
effectScope实现依赖自动清理
二、核心函数解析
1. mergeReactiveObjects - 深度合并响应式对象
TypeScript
function mergeReactiveObjects(target, patchToApply) {
// 处理 Map/Set 类型
if (target instanceof Map && patchToApply instanceof Map) {
patchToApply.forEach((value, key) => target.set(key, value))
}
// 处理普通对象
else {
for (const key in patchToApply) {
const subPatch = patchToApply[key]
// 递归合并嵌套对象
if (isPlainObject(targetValue) && isPlainObject(subPatch)) {
target[key] = mergeReactiveObjects(targetValue, subPatch)
} else {
target[key] = subPatch
}
}
}
}
核心作用:实现 $patch 的深度状态合并,支持 Map/Set 等复杂类型,确保响应式更新正确触发。
2. createOptionsStore - 选项式 Store 适配器
TypeScript
function createOptionsStore(id, options, pinia) {
const { state, actions, getters } = options
// 转换为 Composition API 形式
function setup() {
const localState = toRefs(pinia.state.value[id])
return assign(localState, actions, computedGetters)
}
// 最终调用 Setup API 的创建方法
return createSetupStore(id, setup, options, pinia, true)
}
实现要点:
- 将 Options 形式转换为 Composition API 形式
- 使用
toRefs保持响应式 - 通过
computed包装 getters 实现缓存
3. createSetupStore - Composition API 核心实现
TypeScript
function createSetupStore($id, setup, options, pinia) {
// 创建副作用作用域
const scope = effectScope()
const setupStore = scope.run(() => setup({ action }))!
// 处理响应式状态
for (const key in setupStore) {
const prop = setupStore[key]
if (isRef(prop) || isReactive(prop)) {
// 同步状态到全局 pinia.state
pinia.state.value[$id][key] = prop
} else if (typeof prop === 'function') {
// 包装 Action
setupStore[key] = action(prop, key)
}
}
// 应用插件
pinia._p.forEach(extender => {
assign(store, extender({ store, pinia }))
})
}
核心逻辑:
- 副作用隔离:通过
effectScope管理整个 Store 的副作用 - 状态同步:自动将 setup 返回的 ref/reactive 同步到全局状态树
- Action 增强:通过
action包装器实现$onAction订阅
三、关键机制详解
1. Action 处理机制
TypeScript
function action<Fn extends _Method>(fn: Fn, name: string): Fn {
const wrappedAction = function (this: any) {
// 触发 action 订阅回调
triggerSubscriptions(actionSubscriptions, {
args,
name,
store,
after,
onError
})
try {
const ret = fn.apply(store, args)
// 处理 Promise 链
if (ret instanceof Promise) {
return ret.then(value => {
triggerSubscriptions(afterCallbackList, value)
return value
})
}
} catch (error) {
triggerSubscriptions(onErrorCallbackList, error)
}
}
return wrappedAction
}
核心功能:
- 自动添加
$onAction订阅支持 - 统一处理同步/异步错误
- 提供
after和onError生命周期钩子
2. Getter 缓存机制
TypeScript
// 处理 Options API 的 getters
const computedGetters = Object.keys(getters).reduce((acc, name) => {
acc[name] = computed(() => {
setActivePinia(pinia)
return getters[name].call(store, store)
})
return acc
}, {})
实现原理:
- 使用 Vue 的
computed实现缓存 - 自动绑定 Store 上下文(
this) - 在 getter 访问时自动激活当前 Pinia 实例
3. 响应式状态同步
TypeScript
// 将 setup 返回的状态同步到全局状态树
for (const key in setupStore) {
if (isRef(prop) || isReactive(prop)) {
if (!isOptionsStore) {
pinia.state.value[$id][key] = prop
}
}
}
设计要点:
- 自动检测 ref/reactive 对象
- 通过
toRef/toRefs保持响应式链接 - 支持服务端渲染(SSR)状态同步
四、高级特性实现
1. 热更新(HMR)支持
TypeScript
store._hotUpdate = markRaw((newStore) => {
// 合并新旧状态
newStore._hmrPayload.state.forEach(stateKey => {
if (stateKey in store.$state) {
const newStateTarget = newStore.$state[stateKey]
if (isPlainObject(newStateTarget)) {
patchObject(newStateTarget, oldStateSource)
}
}
})
// 更新 getters/actions
for (const actionName in newStore._hmrPayload.actions) {
store[actionName] = action(newStore[actionName], actionName)
}
})
实现机制:
- 通过
_hmrPayload记录状态元数据 - 使用
patchObject深度合并状态对象 - 动态替换 actions/getters 保持响应性
2. 插件系统集成
TypeScript
pinia._p.forEach(extender => {
const extensions = scope.run(() => extender({
store,
app: pinia._a,
pinia,
options: optionsForPlugin
}))
assign(store, extensions)
})
扩展能力:
- 可访问完整的 Store 上下文
- 支持添加新状态/方法
- 可拦截 action 执行过程
五、性能优化策略
-
响应式优化:
- 使用
markRaw标记不需要响应化的对象 - 通过
shallowRef优化大型数据集 - 批量更新通过
$patch减少触发次数
- 使用
-
内存管理:
TypeScript function $dispose() { scope.stop() pinia._s.delete($id) }- 通过
effectScope.stop()自动清理所有副作用 - 支持手动销毁 Store 释放内存
- 通过
-
类型系统优化:
- 使用条件类型处理 Options/Setup API 类型推断
TypeScript type StoreState<SS> = SS extends Store<infer S> ? UnwrapRef<S> : ...- 精确推导 Action/Getter 类型
总结:Pinia 架构设计亮点
-
分层架构:
Text ┌─────────────┐ │ User Code │ └──────┬──────┘ │ ┌──────▼──────┐ │ Store │ └──────┬──────┘ │ ┌──────▼──────┐ │ Pinia Core │ └──────┬──────┘ │ ┌──────▼──────┐ │ Vue Reactivity │ └───────────────┘ -
响应式集成:
- 深度集成 Vue3 响应式系统
- 利用
effectScope实现精准的依赖追踪
-
扩展性设计:
- 插件系统与 Vue 生态无缝集成
- 支持多种 Store 定义方式
-
类型安全:
- 全流程 TypeScript 类型支持
- 精确推导 Options/Setup 类型