前置
vue2的响应式原理
它只能监听指定对象的、指定属性的 getter 和 setter。所以当对象或数组新增属性时,vue2无法为新增的属性增加响应性。
1 2 3 4
| Object.defineProperty(target, key, { set(newVal) {}, get(key) {} })
|
vue3的响应式系统
reactive
简单实现reactive,核心有几部分
effect:响应式的依赖收集和触发的机制的体现
reactive函数:提供出去要使用的函数
track:收集/追踪依赖
trigger:触发依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| let activeEffect = null class reactiveEffect { constructor(fn) { this.fn = fn } run() { activeEffect = this return this.fn() } } const effect = (fn) => { const re = new reactiveEffect(fn) re.run() }
function reactiveFn(target) { return new Proxy(target, { get(target, key, receiver) { track(target, key) return target[key] }, set(target, key, value, receiver) { target[key] = value trigger(target, key) } }) }
function track(target, key) { if (!activeEffect) return let depsMap = targetMap.get(target) if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } let dep = depsMap.get(key) if (!dep) { depsMap.set(key, (dep = new Set())) } dep.add(activeEffect) }
function trigger(target, key) { let depsMap = targetMap.get(target) if (!depsMap) return const dep = depsMap.get(key) if (dep) dep.forEach(eff => { eff.fn() }) }
|
1 2 3 4 5 6 7 8 9 10
| const student = { name: 'Adam', age: '18' } const proxyStudent = reactiveFn(student) effect(() => { document.querySelector('.wrap').innerHTML = proxyStudent.name + proxyStudent.age }) proxyStudent.age = 19
|
ref
reactive 只能构建复杂数据类型的响应性,proxy就是这样。vue为我们提供了ref来解决这个问题。比较不熟悉的是 gett和set
ref 方法
:接收任意数据
ref 方法
:生成RefC实例,并进行返回
ref 方法
:利用 get 和set 监听getter、setter
行为,以便执行依赖收集和依赖触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class RefC { constructor(value) { this._value = value }
get value() { if (activeEffect) { console.error('reffff', ref) const dep = ref.dep || (ref.dep = new Set()) dep.add(activeEffect) } return this._value }
set value(newVal) { this._value = newVal if (ref.dep) ref.dep.forEach(eff => eff.fn()) } }
function ref(value) { return new RefC(value) }
|
1 2 3 4 5 6 7
| const v = '小明' const refVar = ref(v) effect(() => { document.querySelector('.wrap').innerHTML = refVar.value }) refVar.value = '小红'
|
参考链接
https://juejin.cn/post/7186248802423013432
编译时、运行时的源码解析:
https://blog.csdn.net/qq_34618600/article/details/140893125