源码版本 Vue3.2.24
废话不多说,直接开始!!!
源码地址:packages/reactivity/reactive.ts
先看一下在 Vue3 中定义的几个用来标记目标对象 target
的类型的ReactiveFlags
,下面先是枚举的属性
export const enum ReactiveFlags {
SKIP = '__v_skip',
IS_REACTIVE = '__v_isReactive',
IS_READONLY = '__v_isReadonly',
RAW = '__v_raw'
}
export interface Target {
[ReactiveFlags.SKIP]?: boolean // 不做响应式处理的数据
[ReactiveFlags.IS_REACTIVE]?: boolean // target 是否是响应式
[ReactiveFlags.IS_READONLY]?: boolean // target 是否是只读
[ReactiveFlags.RAW]?: any // 表示 proxy 对应的源数据,target 已经是 proxy 对象时会有该属性
}
对非只读数据调用 createReactiveObject()
创建响应式
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export function reactive(target: object) {
// if trying to observe a readonly proxy, return the readonly version. 如果目标对象是一个只读的响应数据,则直接返回目标对象
if (target && (target as Target)[ReactiveFlags.IS_READONLY]) {
return target
}
// 否则调用 createReactiveObject 创建 observe
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap
)
}
这里代码很简单,主要就是调用 createReactiveObject()
/**
* @description:
* @param {target} 目标对象
* @param {isReadonly} 是否只读
* @param {baseHandlers} 基本类型的handlers
* @param {collectionHandlers} 主要针对(set、map、weakSet、weakMap)的 handlers
*/
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
// typeof 不是 object 类型的,在开发模式抛出警告,生产环境直接返回目标对象
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// 已经经是响应式的就直接返回(取ReactiveFlags.RAW 属性会返回true,因为进行reactive的过程中会用weakMap进行保存,通过target能判断出是否有ReactiveFlags.RAW属性)
// 例外:对reactive对象进行readonly()
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
// target already has corresponding Proxy 对已经Proxy的,则直接从WeakMap数据结构中取出这个Proxy对象
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
// only a whitelist of value types can be observed. 只对targetTypeMap类型白名单中的类型进行响应式处理
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
const proxy = new Proxy( // proxy代理target
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
proxyMap.set(target, proxy) // 添加到 map 里
return proxy
}
大概了解了这个方法里要做的事,可以看出一个很重要的东西,就是proxy
的第二个参数 handlers
。其中baseHandlers
处理数组,对象,collectionHandlers
处理 Map
、Set
、WeakMap
、WeakSet
在 basehandlers 中包含了四种 handler
mutableHandlers
可变处理readonlyHandlers
只读处理shallowReactiveHandlers
浅观察处理(只观察目标对象的第一层属性)shallowReadonlyHandlers
浅观察 && 只读处理其中 readonlyHandlers
、shallowReactiveHandlers
、shallowReadonlyHandlers
都是 mutableHandlers
的变形版本。
所以接下来只看mutableHandlers
的具体实现。
源码地址:packages/reactivity/src/baseHandlers.ts
mutableHandlers
定义是这样的
const get = /*#__PURE__*/ createGetter()
const set = /*#__PURE__*/ createSetter()
export const mutableHandlers: ProxyHandler<object> = {
get, // 用于拦截对象的读取属性操作
set, // 用于拦截对象的设置属性操作
deleteProperty, // 用于拦截对象的删除属性操作
has, // 检查一个对象是否拥有某个属性
ownKeys // 针对 getOwnPropertyNames, getOwnPropertySymbols, keys 的代理方法
}
这里:
get
has
ownKeys
会触发依赖收集 track()
set
deleteProperty
会触发更新 trigger()
其中有两个重要的方法就是 get
和 set
对应的 createGetter
和 createSetter
/**
* @description: 用于拦截对象的读取属性操作
* @param {isReadonly} 是否只读
* @param {shallow} 是否浅观察
*/
function createGetter(isReadonly = false, shallow = false) {
/**
* @description:
* @param {target} 目标对象
* @param {key} 需要获取的值的键值
* @param {receiver} 如果遇到 setter,receiver则为setter调用时的this值
*/
return function get(target: Target, key: string | symbol, receiver: object) {
// ReactiveFlags 是在reactive中声明的枚举值,如果key是枚举值则直接返回对应的布尔值
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly
} else if (
// 如果key是raw receiver 指向调用者,则直接返回目标对象。
// 这里判断是为了保证触发拦截 handle 的是 proxy 本身而不是 proxy 的继承者
// 触发拦的两种方式:一是访问 proxy 对象本身的属性,二是访问对象原型链上有 proxy 对象的对象的属性,因为查询会沿着原型链向下找
key === ReactiveFlags.RAW &&
receiver ===
(isReadonly
? shallow
? shallowReadonlyMap
: readonlyMap
: shallow
? shallowReactiveMap
: reactiveMap
).get(target)
) {
return target
}
const targetIsArray = isArray(target)
// 如果目标对象 不为只读、是数组、key属于arrayInstrumentations:['includes', 'indexOf', 'lastIndexOf']方法之一,即触发了这三个方法之一
if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {
// 通过 proxy 调用,arrayInstrumentations[key]的this一定指向 proxy
return Reflect.get(arrayInstrumentations, key, receiver)
}
const res = Reflect.get(target, key, receiver)
// 如果 key 是 symbol 内置方法,或者访问的是原型对象__proto__,直接返回结果,不收集依赖
if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
return res
}
// 不是只读类型的 target 就收集依赖。因为只读类型不会变化,无法触发 setter,也就会触发更新
if (!isReadonly) {
track(target, TrackOpTypes.GET, key) // 收集依赖,存储到对应的全局仓库中
}
// 如果是浅观察,不做递归转化,就是说对象有属性值还是对象的话不递归调用 reactive()
if (shallow) {
return res
}
// 如果get的结果是ref
if (isRef(res)) {
// ref unwrapping - does not apply for Array + integer key.
// 返回 ref.value,数组除外
const shouldUnwrap = !targetIsArray || !isIntegerKey(key)
return shouldUnwrap ? res.value : res
}
// 由于 proxy 只能代理一层,如果子元素是对象,需要递归继续代理
if (isObject(res)) {
// Convert returned value into a proxy as well. we do the isObject check
// here to avoid invalid value warning. Also need to lazy access readonly
// and reactive here to avoid circular dependency.
return isReadonly ? readonly(res) : reactive(res)
}
return res
}
}
track()
依赖收集放到后面,和派发更新一起
源码地址:packages/reactivity/src/baseHandlers.ts
/**
* @description: 拦截对象的设置属性操作
* @param {shallow} 是否是浅观察
*/
function createSetter(shallow = false) {
/**
* @description:
* @param {target} 目标对象
* @param {key} 设置的属性的名称
* @param {value} 要改变的属性值
* @param {receiver} 如果遇到 setter,receiver则为setter调用时的this值
*/
return function set(
target: object,
key: string | symbol,
value: unknown,
receiver: object
): boolean {
let oldValue = (target as any)[key]
// 如果模式不是浅观察
if (!shallow) {
// 拿新值和老值的原始值,因为新传入的值可能是响应式数据,如果直接和 target 上原始值比较是没有意义的
value = toRaw(value)
oldValue = toRaw(oldValue)
// 目标对象不是数组,旧值是ref,新值不是ref,则直接赋值,注意这里提到ref
if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
oldValue.value = value
return true
}
} else {
// in shallow mode, objects are set as-is regardless of reactive or not
}
// 检查对象是否有这个属性
const hadKey =
isArray(target) && isIntegerKey(key)
? Number(key) < target.length
: hasOwn(target, key)
// 赋值
const result = Reflect.set(target, key, value, receiver)
// don't trigger if target is something up in the prototype chain of original
// receiver 是 proxy 实例才派发更新,防止通过原型链触发拦截器触发更新
if (target === toRaw(receiver)) {
if (!hadKey) {
// 如是不存在则trigger ADD
trigger(target, TriggerOpTypes.ADD, key, value)
} else if (hasChanged(value, oldValue)) {
// 如果新旧值不相等则trigger SET
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
}
return result
}
}
trigger()
派发更新放到后面
/**
* @description: 用于拦截对象的删除属性操作
* @param {target} 目标对象
* @param {key} 键值
* @return {Boolean}
*/
function deleteProperty(target: object, key: string | symbol): boolean {
// 检查一个对象是否包含当前key
const hadKey = hasOwn(target, key)
const oldValue = (target as any)[key]
// Reflect 作用在于完成目标对象的默认,这里即指删除
const result = Reflect.deleteProperty(target, key)
// 如果该值被成功删除则调用 trigger(trigger 为 effect 里的方法,effect 为 reactive 的核心)
if (result && hadKey) {
trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)
}
return result
}
/**
* @description: 检查一个对象是否拥有某个属性
* @param {target} 目标对象
* @param {key} 键值
* @return {Boolean}
*/
function has(target: object, key: string | symbol): boolean {
const result = Reflect.has(target, key)
if (!isSymbol(key) || !builtInSymbols.has(key)) {
// track 也为 effect 里的方法
track(target, TrackOpTypes.HAS, key)
}
return result
}
// 返回一个由目标对象自身的属性键组成的数组
function ownKeys(target: object): (string | symbol)[] {
track(target, TrackOpTypes.ITERATE, isArray(target) ? 'length' : ITERATE_KEY)
return Reflect.ownKeys(target)
}
接下来看一下依赖收集和派发更新的内容。相关代码全部在 effect.ts
文件中。
源码地址:packages/reactivity/src/effect.ts -145行
主要内容如下:
effect
入口函数track
依赖收集trigger
派发更新cleanupEffect
清除 effect
stop
停止effect
trackStack
收集栈的暂停(pauseTracking
)、恢复(enableTracking
)和重置(resetTracking
)这里主要就是暴露一个创建 effect
的方法
export function effect<T = any>(
fn: () => T,
options?: ReactiveEffectOptions
): ReactiveEffectRunner {
// 如果已经是 effect 函数,就直接重置为原始对象
if ((fn as ReactiveEffectRunner).effect) {
fn = (fn as ReactiveEffectRunner).effect.fn
}
const _effect = new ReactiveEffect(fn)
// 创建`effect`
if (options) {
extend(_effect, options)
if (options.scope) recordEffectScope(_effect, options.scope)
}
// 如果 lazy 不为真就直接执行一次 effect。计算属性的 lazy 为 true
if (!options || !options.lazy) {
_effect.run()
}
const runner = _effect.run.bind(_effect) as ReactiveEffectRunner
runner.effect = _effect
return runner
}
可以看出主要的就是在 effect
里使用 new ReactiveEffect
创建了一个 _effect
实例,并且函数最后返回的 runner 方法就是指向 ReactiveEffect
里的 run
方法。换句话说,执行 effect
方法时,实际上就是执行 run
方法。
下面看一下 ReactiveEffect
和 run
方法都干了些什么
这里主要做的就是在依赖收集前用栈数据结构 effectStrack
来做 effect
的执行调试,保证当前 effect
的优先级最高,并及时清除己收集依赖的内存。
需要注意的是标记完成后就会执行 fn()
函数,这个 fn 函数就是副作用函数封闭的函数,如果是在组件渲染,就是 fn 就是组件渲染函数,执行的时候就会就会访问数据,就会触发 target[key]
的 getter
,然后触发 track
进行依赖收集,这也就是 Vue3 的依赖收集过程
// 临时存储响应式函数
const effectStack: ReactiveEffect[] = []
// 依赖收集栈
const trackStack: boolean[] = []
// 最大嵌套深度
const maxMarkerBits = 30
export class ReactiveEffect<T = any> {
active = true
deps: Dep[] = []
// can be attached after creation
computed?: boolean
allowRecurse?: boolean
onStop?: () => void
// dev only
onTrack?: (event: DebuggerEvent) => void
// dev only
onTrigger?: (event: DebuggerEvent) => void
constructor(
public fn: () => T,
public scheduler: EffectScheduler | null = null,
scope?: EffectScope | null
) {
// effectScope 相关处理,在另一个文件effectScope.ts
recordEffectScope(this, scope)
}
run() {
if (!this.active) {
return this.fn()
}
// 如果effectStack栈中没有当前的 effect
if (!effectStack.includes(this)) {
try {
// activeEffect 表示当前依赖收集系统正在处理的 effect, 先把当前 effect 设置为全局全局激活的 effect,在 getter 中会收集 activeEffect 持有的 effect
// 然后入栈
effectStack.push((activeEffect = this))
enableTracking()
// 记录递归深度位数
trackOpBit = 1 << ++effectTrackDepth
// 如果 effect 嵌套层数没有超过 30 层,一般超不了
if (effectTrackDepth <= maxMarkerBits) {
// 给依赖打标记,就是遍历 _effect 实例中的 deps 属性,给每个 dep 的 w 属性标记为 trackOpBit 的值
initDepMarkers(this)
} else {
// 超过就 清除当前 effect 相关依赖 通常情况下不会
cleanupEffect(this)
}
// 在执行 effect 函数,比如访问 target[key],会触发 getter
return this.fn()
} finally {
if (effectTrackDepth <= maxMarkerBits) {
// 完成依赖标记
finalizeDepMarkers(this)
}
// 恢复到上一级
trackOpBit = 1 << --effectTrackDepth
// 重置依赖收集状态
resetTracking()
// 出栈
effectStack.pop()
// 将当前 activeEffect 指向栈最后一个 effect
const n = effectStack.length
activeEffect = n > 0 ? effectStack[n - 1] : undefined
}
}
}
stop() {
if (this.active) {
cleanupEffect(this)
if (this.onStop) {
this.onStop()
}
this.active = false
}
}
}
// 每次 effect 运行都会重新收集依赖, deps 是 effect 的依赖数组, 需要全部清空
function cleanupEffect(effect: ReactiveEffect) {
const { deps } = effect
if (deps.length) {
for (let i = 0; i < deps.length; i++) {
deps[i].delete(effect)
}
deps.length = 0
}
}
track
就是依赖收集器,负责把依赖收集起来统一放到一个依赖管理中心
// targetMap 为依赖管理中心,用于存储响应式函数、目标对象、键之间的映射关系
// 相当于这样
// targetMap(weakmap)={
// target1(map):{
// key1(dep):[effect1,effect2]
// key2(dep):[effect1,effect2]
// }
// }
// 给每个 target 创建一个 map,每个 key 对应着一个 dep
// 用 dep 来收集依赖函数,监听 key 值变化,触发 dep 中的依赖函数
type KeyToDepMap = Map<any, Dep>
const targetMap = new WeakMap<any, KeyToDepMap>()
export function isTracking() {
return shouldTrack && activeEffect !== undefined
}
/**
* @description:
* @param {target} 目标对象
* @param {type} 收集的类型, 函数的定义在下方
* @param {key} 触发 track 的 object 的 key
*/
export function track(target: object, type: TrackOpTypes, key: unknown) {
// 如果当前没有激活 effect,就不用收集
if (!isTracking()) {
return
}
// targetMap 依赖管理中心,用于收集依赖和触发依赖
// 检查targetMap中有没有当前target
let depsMap = targetMap.get(target)
if (!depsMap) {
// 没有则新建一个
targetMap.set(target, (depsMap = new Map()))
}
// deps 来收集依赖函数,当监听的 key 值发生变化时,触发 dep 中的依赖函数
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = createDep()))
}
// 开发环境会触发onTrack, 仅用于调试
const eventInfo = __DEV__
? { effect: activeEffect, target, type, key }
: undefined
trackEffects(dep, eventInfo)
}
这里把当前激活的 effect
收集进对应的 effect
集合,也就是 dep
这里了解一下两个标识符:
dep.n
:n 是 newTracked
的缩写,表示是否是最新收集的(是否当前层)dep.w
:w 是 wasTracked
的缩写,表示是否已经被收集,避免重复收集/**
* @description:
* @param {dep} dep依赖收集器
* @param {debuggerEventExtraInfo}
*/
export function trackEffects(
dep: Dep,
debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
let shouldTrack = false
// 如果 effect 嵌套层数没有超过 30 层
if (effectTrackDepth <= maxMarkerBits) {
if (!newTracked(dep)) {
dep.n |= trackOpBit // set newly tracked 标记新依赖
shouldTrack = !wasTracked(dep)
}
} else {
// Full cleanup mode. 嵌套超限,就切换清除依赖模式
shouldTrack = !dep.has(activeEffect!)
}
// 如果可以收集
if (shouldTrack) {
// 收集当前激活的 effect 作为依赖
dep.add(activeEffect!)
// 当前激活的 effect 收集 dep 集合
activeEffect!.deps.push(dep)
// 开发环境下触发 onTrack 事件
if (__DEV__ && activeEffect!.onTrack) {
activeEffect!.onTrack(
Object.assign(
{
effect: activeEffect!
},
debuggerEventExtraInfo
)
)
}
}
}
trigger
是 track
收集的依赖对应的触发器,也就是负责根据映射关系,获取响应式函数,再派发通知 triggerEffects
进行更新
export function trigger(
target: object,
type: TriggerOpTypes,
key?: unknown,
newValue?: unknown,
oldValue?: unknown,
oldTarget?: Map<unknown, unknown> | Set<unknown>
) {
const depsMap = targetMap.get(target)
// 依赖管理中没有, 代表没有收集过依赖,直接返回
if (!depsMap) {
// never been tracked
return
}
let deps: (Dep | undefined)[] = []
// 触发trigger 的时候传进来的类型是清除类型
if (type === TriggerOpTypes.CLEAR) {
// collection being cleared
// trigger all effects for target
deps = [...depsMap.values()]
} else if (key === 'length' && isArray(target)) {
// 如果是数组类型的,并且是数组的 length 改变时
depsMap.forEach((dep, key) => {
// 如果数组长度变短时,需要做已删除数组元素的 effects 和 trigger
// 也就是索引号 >= 数组最新的length的元素们对应的 effects,要将它们添加进队列准备清除
if (key === 'length' || key >= (newValue as number)) {
deps.push(dep)
}
})
} else {
// schedule runs for SET | ADD | DELETE
// 如果 key 不是 undefined,就添加对应依赖到队列,比如新增、修改、删除
if (key !== void 0) {
deps.push(depsMap.get(key))
}
// also run for iteration key on ADD | DELETE | Map.SET
switch (type) {
case TriggerOpTypes.ADD:
if (!isArray(target)) {
// 往队列中添加关联的所有依赖,准备清除
deps.push(depsMap.get(ITERATE_KEY))
if (isMap(target)) {
deps.push(depsMap.get(MAP_KEY_ITERATE_KEY))
}
} else if (isIntegerKey(key)) {
// new index added to array -> length changes
deps.push(depsMap.get('length'))
}
break
case TriggerOpTypes.DELETE:
if (!isArray(target)) {
deps.push(depsMap.get(ITERATE_KEY))
if (isMap(target)) {
deps.push(depsMap.get(MAP_KEY_ITERATE_KEY))
}
}
break
case TriggerOpTypes.SET:
if (isMap(target)) {
deps.push(depsMap.get(ITERATE_KEY))
}
break
}
}
// 到这里就拿到了 targetMap[target][key],并存到 deps 里
// 接着是要将对应的 effect 取出,调用 triggerEffects 执行
// 判断开发环境,传入eventInfo
const eventInfo = __DEV__
? { target, type, key, newValue, oldValue, oldTarget }
: undefined
if (deps.length === 1) {
if (deps[0]) {
if (__DEV__) {
triggerEffects(deps[0], eventInfo)
} else {
triggerEffects(deps[0])
}
}
} else {
const effects: ReactiveEffect[] = []
for (const dep of deps) {
if (dep) {
effects.push(...dep)
}
}
if (__DEV__) {
triggerEffects(createDep(effects), eventInfo)
} else {
triggerEffects(createDep(effects))
}
}
}
源码地址:packages/reactivity/src/effect.ts -330行
执行 effect 函数,也就是『派发更新』中的更新了
export function triggerEffects(
dep: Dep | ReactiveEffect[],
debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
// spread into array for stabilization 遍历 effect 的集合函数
for (const effect of isArray(dep) ? dep : [...dep]) {
/**
这里判断 effect !== activeEffect的原因是:不能和当前effect 相同
比如:count.value++,如果这是个effect,会触发getter,track收集了当前激活的 effect,
然后count.value = count.value+1 会触发setter,执行trigger,
就会陷入一个死循环,所以要过滤当前的 effect
*/
if (effect !== activeEffect || effect.allowRecurse) {
if (__DEV__ && effect.onTrigger) {
effect.onTrigger(extend({ effect }, debuggerEventExtraInfo))
}
// 如果有 scheduler 就执行,计算属性有 scheduler
if (effect.scheduler) {
effect.scheduler()
} else {
effect.run() // 执行 effect 函数
}
}
}
}
源码地址:packages/reactivity/src/ref.ts
直接结合源码来看,ref
接收一个可选的 unknown
做为入参,接着直接调用 createRef
;createRef
先判断 value
是否已经是一个 ref
, 如果是则直接返回,否则 new RefImpl()
创建的。
// 判断是不是 ref
export function isRef(r: any): r is Ref {
return Boolean(r && r.__v_isRef === true)
}
export function ref(value?: unknown) {
return createRef(value, false)
}
/**
* @description: 创建 ref
* @param {rawValue} 原始值
* @param {shallow} 是否是浅观察
*/
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) { // 如果已经是 ref 就直接返回
return rawValue
}
// 调用 RefImpl 创建并返回 ref
return new RefImpl(rawValue, shallow)
}
// 创建一个浅层 ref
export function shallowRef(value?: unknown) {
return createRef(value, true)
}
// 卸载一个 ref
export function unref<T>(ref: T | Ref<T>): T {
return isRef(ref) ? (ref.value as any) : ref
}
从上面我们知道 ref
对象是通过 new RefImpl()
创建的,RefImpl
类的实现比较简单:判断是不是浅观察,如果是浅观察直接构造一个 ref
返回,不是则将 rawValue
转换成 reactive
再构造一个 ref
返回
class RefImpl<T> {
private _value: T
private _rawValue: T
public dep?: Dep = undefined
public readonly __v_isRef = true // 每一个 ref 实例下都有一个__v_isRef 的只读属性,标识它是一个 ref
constructor(value: T, public readonly _shallow: boolean) {
this._rawValue = _shallow ? value : toRaw(value) // 判断是不是浅比较,如果不是就拿老值
this._value = _shallow ? value : toReactive(value) // 判断是不是浅比较,如果不是就调toReactive(): 如果是对象就用reactive()包裹,否则返回本身
}
get value() {
trackRefValue(this) // 进行依赖收集
return this._value
}
set value(newVal) {
// 如果是浅比较,就取新值,不是就取老值
newVal = this._shallow ? newVal : toRaw(newVal)
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal // 值已更换,重新赋值
this._value = this._shallow ? newVal : toReactive(newVal)
triggerRefValue(this, newVal) // 触发依赖 派发更新
}
}
}
进行ref
依赖收集的工作:
trackEffects
进行依赖收集export function trackRefValue(ref: RefBase<any>) {
if (isTracking()) { // 如果激活了 effect,就收集
ref = toRaw(ref)
if (!ref.dep) { // 如果该属性没有没有收集过依赖函数,就创建一个 dep,用来存放依赖 effect
ref.dep = createDep()
}
if (__DEV__) {
trackEffects(ref.dep, {
target: ref,
type: TrackOpTypes.GET,
key: 'value'
})
} else {
trackEffects(ref.dep) // 调用本文上面的 trackEffects 收集依赖
}
}
}
进行 ref
派发更新,源码比较清晰:区分一下开发环境,然后执行本文上面的 triggerEffects
执行对应在的 effect
函数进行更新
export function triggerRefValue(ref: RefBase<any>, newVal?: any) {
ref = toRaw(ref)
if (ref.dep) {
if (__DEV__) {
triggerEffects(ref.dep, {
target: ref,
type: TriggerOpTypes.SET,
key: 'value',
newValue: newVal
})
} else {
triggerEffects(ref.dep)
}
}
}
到这里,Vue3 的响应式对象的源码就基本上就看完了
如果本文对你有一丁点帮助,点个赞支持一下吧,感谢感谢