vue3—数据响应
定义数字 a 与数据 b、且 b = a + 10,假设数据 a 每次发生改变时,我们都想实时打印 b 的值
基础
let a, b;
a = 10;
b = a + 10;
console.log(b); // 20
a = 20;
b = a + 10;
console.log(b); // 30
非常明显的,每次我们改变 a 的数据时,我们都需要手动调用去更新 b 的值,最后才会得到我们想要的值
基础的优化
let a, b;
a = 10;
changeUpdate();
a = 20;
changeUpdate();
function changeUpdate() {
b = a + 10;
console.log(b);
}
优化版实际上只是将 b 更新的规则封装,但本质上每次 a 的值发生变化,还是需要我们手动去更新。
那有没有一种方案是: 我只要改变 a 的值 、设置需要更新对象 b 的规则,它自动触发呢
vue3版
安装
npm i @vue/reactivity
ref
// 引入
const { effect, ref } = require("@vue/reactivity");
let a, b;
// 定义响应式的数据 a
a = ref(10);
// 设置更新规则
function changeUpdate() {
b = a.value + 10;
console.log(b);
}
effect(changeUpdate);
// 再次更新 a 的值
a.value = 20;
reactive
const { effect, reactive } = require("@vue/reactivity");
// 定义响应式的数据 a
a = reactive({
value: 10,
});
上面的例子 仅需对声明的数据 a 进行处理,设定更新规则,然后 a 的值更新之后就会执行
简单实现响应式
ref
// 全局存储当前需要收集的依赖
let currentEffect;
// 收集依赖
class Dep {
constructor(val) {
// 利用 Set 防止依赖重复收集
this.effects = new Set();
// 创建类时定义值、 利用 get set 就能监听到其的获取和更新
this._val = val;
}
depend() {
// 收集当前存储的依赖
if (currentEffect) {
this.effects.add(currentEffect);
}
}
notice() {
// 发布当前的依赖
this.effects.forEach((effect) => {
effect();
});
}
get value() {
// 定义值时 订阅
this.depend();
return this._val;
}
set value(newVal) {
this._val = newVal;
// 值更新完毕之后 发布
this.notice();
}
}
function effect(fn) {
// 收集当前依赖, 收集之后清空
currentEffect = fn;
// 定义之后先执行一次
fn();
currentEffect = null;
}
// 声明响应式数据 类似与 ref
let a = new Dep(10);
// 定义更新规则
effect(() => {
let b = a.value + 10;
console.log(b);
});
// 再次更新
a.value = 20;
reactive
// 全局存储当前需要收集的依赖
let currentEffect;
// 收集依赖
class Dep {
constructor(val) {
// 利用 Set 防止依赖重复收集
this.effects = new Set();
// 创建类时定义值、 利用 get set 就能监听到其的获取和更新
this._val = val;
}
depend() {
// 收集当前存储的依赖
if (currentEffect) {
this.effects.add(currentEffect);
}
}
notice() {
// 发布当前的依赖
this.effects.forEach((effect) => {
effect();
});
}
get value() {
// 定义值时 订阅
this.depend();
return this._val;
}
set value(newVal) {
this._val = newVal;
// 值更新完毕之后 发布
this.notice();
}
}
function effect(fn) {
// 收集当前依赖, 收集之后清空
currentEffect = fn;
// 定义之后先执行一次
fn();
currentEffect = null;
}
let targetMap = new Map();
// get set 相同的代码封装
function getDep(target, key) {
let depsMap = targetMap.get(target);
if (!depsMap) {
depsMap = new Map();
targetMap.set(target, depsMap);
}
let dep = depsMap.get(key);
if (!dep) {
dep = new Dep();
depsMap.set(key, dep);
}
return dep;
}
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
// 每一个 target 都对应一个 Map、而对应的 Map 中 key 存储的是其对应的 依赖收集类 dep
// 最后的目的是 为了获取到每个 key 的 dep 实例对象,让其收集依赖
let dep = getDep(target, key);
// 收集依赖
dep.depend();
// Reflect 和 Object 方法的一些区别
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/Comparing_Reflect_and_Object_methods
return Reflect.get(target, key);
},
set(target, key, val) {
let dep = getDep(target, key);
let result = Reflect.set(target, key, val);
// 值改变时 发布依赖
dep.notice();
return result;
},
});
}
// 声明响应式数据
let a = new reactive({
value: 10,
});
// 定义更新规则
effect(() => {
let b = a.value + 10;
console.log(b);
});
// 再次更新
a.value = 20;