[Vue 源码] Vue 3.2 - Ref 原理
运行结果
代码示例
<script src="./dist/reactivity.global.js"></script>
<body>
<div id="app"></div>
<script>
let { ref, effect } = VueReactivity
let state = ref(false)
effect(() => {
app.innerHTML = `ref is ${state.value} `
})
setTimeout(() => {
state.value = true
}, 2000)
</script>
执行第一句代码:ref(false)
, 调用 ref 函数
第一: ref函数,调用 createRef 函数。
export function ref(value?: unknown) {
return createRef(value, false)
}
第二:createRef 函数中, 通过 new RefImpl 实例化 ref对象。
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
第三:调用 RefImpl 的 constructor 构造函数。构造函数中初始化 ref 实例对象的 _value 和 _rawValue, 本例中是将 false 传给 toRective, 如果 value 是一个对象则将 通过 reactive 函数包装成 响应式对象,本例中直接返回 false。
第四:返回创建好的 ref 对象。
constructor(value: T, public readonly __v_isShallow: boolean) {
this._rawValue = __v_isShallow ? value : toRaw(value)
this._value = __v_isShallow ? value : toReactive(value)
}
第四:开始执行第二句代码 effect(() => { app.innerHTML = `ref is ${state.value} ` })
, effect 函数调用创建 ReactiveEffect 对象,将 activeEffect 对象置为当前的 ReactiveEffect 对象。调用 run 方法,调用 () => { app.innerHTML = `ref is ${state.value}` }
函数
第五:在该函数中触发 state 响应式 ref 对象 value 属性的 getter 操作。
-
通过 trackRefValue 函数 收集依赖到 ref.deps 当中。
{dep: [ReactiveEffect]}
-
返回_value 值,也就是 false
get value() {
trackRefValue(this)
return this._value
}
- app.innerHTML = -_value.
初始渲染完成。
更新阶段
执行第一句代码: setTimeout(() => { state.value = true }, 2000)
触发 响应式对象 ref 的 value 属性的 setter 操作。
- 修改 _value 为新值
this._rawValue = newVal
this._value = useDirectValue ? newVal : toReactive(newVal)
- triggerRefValue 来触发依赖列表
set value(newVal) {
const useDirectValue =
this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)
newVal = useDirectValue ? newVal : toRaw(newVal)
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = useDirectValue ? newVal : toReactive(newVal)
triggerRefValue(this, newVal)
}
}
-
triggerRefValue 函数中 触发一系列 trigger 操作,我们再前面的文章多次聊到过。这里直接执行 ref 对象依赖列表 dep属性 中 ReactiveEffec 对象的 run 方法。也就是
() => { app.innerHTML = ref is ${state.value} }
-
再次通过 state.value 触发 ref 对象 value 属性的 getter 操作,返回最新值,渲染,然后再次追踪依赖。
-
等待下一次的更新。
自此更新完毕。
转载自:https://juejin.cn/post/7208907027840532536