昨天更新了v2的手写版,今天更新一下v3的吧.其实和vue2实现的思路也是差不多的,但是在一些api的选择上和细节处理上优化了不少,他主要也分为3个部分,reactive,track,trigger
reactive - 响应式处理
我们这里是写一个简单的响应式,所以就省略了对目标对象的一些访问、删除、查询、设置的操作的劫持.着重分析一些set和get函数,因为这两个函数中涉及到依赖收集和派发更新的操作。分析的时候我们会删除部分代码,只分析主流程。,首先会使用Reflect.get进行求值, 然后判断是否是只读的,如果不是就调用track进行依赖收集,
更新响应式对象的属性的时候会触发set函数,set函数内部的主要步骤也是三个,首先获取这个属性的oldValue,然后通过Reflect.set对属性进行赋值操作,最后调用trigger进行派发更新
const isObject = (val) => val !== null && typeof val === 'object';
function reactive(target) {
if (!isObject(target)) return;
const handler = {
get(target, key, receiver) {
let result = Reflect.get(target, key, receiver);
track(target, key);
return result;
},
set(target, key, value, receiver) {
let oldValue = Reflect.get(target, key, receiver);
let result = true;
if (oldValue !== value) {
result = Reflect.set(target, key, value, receiver);
trigger(target, key);
}
return result;
}
};
return new Proxy(target, handler);
}
track - 依赖收集
在进行分析依赖收集的流程之前我们要先弄明白一个概念targetMap, 它是一个WeakMap的数据结构,主要用于存放用来存储原始数据->key->deps这样的一个映射关系.
let targetMap = new WeakMap();
function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let deps = depsMap.get(key);
if (!deps) {
depsMap.set(key, (deps = new Set()));
}
deps.add(activeEffect);
}
trigger - 派发更新
- 首先获取当前target对应的依赖映射表,如果没有,说明这个target没有依赖,直接返回,否则进行下一步
- 然后声明一个集合和一个向集合中添加元素的方法
- 将当前key的所有依赖集合循环遍历,按照对应的方式运行
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) {
return;
}
let deps = depsMap.get(key);
if (deps) {
deps.forEach((effect) => {
effect();
});
}
}
effect - 副作用函数
当我们向effect中传递一个原始的函数的时候,会立即执行一次,这里简写一下,源码是2个参数,第二个参数是配置参数,用于控制第一个参数的调度行为。判断当前的函数是否已经是副作用函数,如果是就将获取当前响应式函数的原始函数。然后将参数传递给createReactiveEffect来创建响应式副作用函数。最后执行返回的响应式副作用函数。
let activeEffect = null;
function watchEffect(effect) {
activeEffect = effect;
effect();
activeEffect = null;
}
ref
和reactive差不多
// 判断一个对象是不是对象 是的话就用reactive代理
const convert = (val) => (isObject(val) ? reactive(val) : val);
class RefImpl {
constructor(rawValue) {
this._rawValue = rawValue;
this.__v__isRef = true;
// 判断 _rawValue 是否是一个对象
// 如果是对象调用reactive使用 proxy来代理
// 不是返回 _rawValue 本身
this._value = convert(rawValue);
}
get value() {
track(this, 'value');
return this._value;
}
set value(newValue) {
if (newValue !== this._value) {
this._rawValue = newValue;
this._value = convert(this._rawValue);
trigger(this, 'value');
}
}
}
function ref(rawValue) {
return new RefImpl(rawValue);
}
测试
```const obj = reactive({
name: 'qqq',
age: 23
});
watchEffect(() => {
console.log('执行副作用函数', obj.age);//执行副作用函数 23
//执行副作用函数 24
});
obj.age++;