feat: vue3响应式原理

This commit is contained in:
= 2024-06-01 04:29:31 +08:00
parent 61d989f779
commit f3df94b51a
7 changed files with 538 additions and 0 deletions

View File

@ -0,0 +1,41 @@
const targetMap = new WeakMap() // 用原始对象作为key依赖映射作为value
function track(target, key) {
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(effect)
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if(!depsMap) return
const deps = depsMap.get(key)
deps.forEach(effect => {
effect()
});
}
// 测试
let product = {price: 5, quantity: 2}
let total = 0
let effect = ()=>{ // 副作用函数
total = product.price * product.quantity
}
track(product, 'quantity') // 跟踪这个key并记录副作用函数
effect() // 首次执行副作用函数
console.log(total);
product.quantity = 3
trigger(product, 'quantity') // 重新触发所有副作用
console.log(total);
/* total
只要保存这个副作用当与之关联的数据发生变化时执行副作用就行了
*/

View File

@ -0,0 +1,59 @@
const targetMap = new WeakMap() // 用原始对象作为key依赖映射作为value
function track(target, key) {
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(effect)
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if(!depsMap) return
const deps = depsMap.get(key)
deps.forEach(effect => {
effect()
});
}
function reactive(target){
const hander = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
track(target, key)
return result
},
set(target, key, value, receiver) {
let oldValue = target[key]
let result = Reflect.set(target, key, value, receiver)
if (oldValue !== value){
trigger(target, key)
}
return result
}
}
return new Proxy(target, hander)
}
const product = new reactive({price: 5, quantity: 2})
let total = 0
let effect = ()=>{
total = product.price * product.quantity // price和quantity都被跟踪了
}
effect()
console.log(total);
product.quantity = 3
console.log(total);
product.price = 100
console.log(total);

View File

@ -0,0 +1,87 @@
const targetMap = new WeakMap() // 用原始对象作为key依赖映射作为value
let activeEffect = null // 保存当前的需要订阅通知的effect
function track(target, key) {
if(activeEffect) {
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) // 将efect添加进通知set
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if(!depsMap) return
const deps = depsMap.get(key)
deps.forEach(effect => {
effect()
});
}
function reactive(target){
const hander = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
track(target, key)
return result
},
set(target, key, value, receiver) {
let oldValue = target[key]
let result = Reflect.set(target, key, value, receiver)
if (oldValue !== value){
trigger(target, key)
}
return result
}
}
return new Proxy(target, hander)
}
// 创建ref为基本数据类型赋予响应式功能
function ref(raw) {
const r = {
get value(){
track(r, 'value')
return raw
},
set value(newVal){
raw = newVal
trigger(r, 'value')
}
}
return r
}
function effect(effect){
activeEffect = effect
activeEffect()
activeEffect = null
}
const product = new reactive({price: 5, quantity: 2})
let tax = ref(5) // 固定的商品税
let total = 0
effect(()=>{
total = tax.value + product.price * product.quantity // price和quantity都被跟踪了
})
console.log(total);
product.quantity = 4
product.price = 5
console.log(total);
tax.value = 10 // 修改固定的商品税
console.log(total);

View File

@ -0,0 +1,90 @@
const targetMap = new WeakMap() // 用原始对象作为key依赖映射作为value
let activeEffect = null // 保存当前的需要订阅通知的effect
function track(target, key) {
if(activeEffect) {
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) // 将efect添加进通知set
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if(!depsMap) return
const deps = depsMap.get(key)
deps.forEach(effect => {
effect()
});
}
function reactive(target){
const hander = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
track(target, key)
return result
},
set(target, key, value, receiver) {
let oldValue = target[key]
let result = Reflect.set(target, key, value, receiver)
if (oldValue !== value){
trigger(target, key)
}
return result
}
}
return new Proxy(target, hander)
}
// 创建ref为基本数据类型赋予响应式功能
function ref(raw) {
const r = {
get value(){
track(r, 'value')
return raw
},
set value(newVal){
raw = newVal
trigger(r, 'value')
}
}
return r
}
function effect(effect){
activeEffect = effect
activeEffect()
activeEffect = null
}
function computed(getter){
let result = ref()
effect(()=>(result.value = getter()))
return result
}
const product = new reactive({price: 5, quantity: 2})
const total = computed(()=>{
return product.price * product.quantity
})
console.log(total.value);
product.price = 3
console.log(total.value);
product.quantity = 10
console.log(total.value);

View File

@ -0,0 +1,117 @@
const targetMap = new WeakMap() // 用原始对象作为key依赖映射作为value
let activeEffect = null // 保存当前的需要订阅通知的effect
function track(target, key) {
if(activeEffect) {
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) // 将efect添加进通知set
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if(!depsMap) return
const deps = depsMap.get(key)
deps.forEach(effect => {
effect()
});
}
function reactive(target){
const hander = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
track(target, key)
return result
},
set(target, key, value, receiver) {
let oldValue = target[key]
let result = Reflect.set(target, key, value, receiver)
if (oldValue !== value){
trigger(target, key)
}
return result
}
}
return new Proxy(target, hander)
}
// 创建ref为基本数据类型赋予响应式功能
function ref(raw) {
const r = {
get value(){
track(r, 'value')
return raw
},
set value(newVal){
raw = newVal
trigger(r, 'value')
}
}
return r
}
function effect(effect){
activeEffect = effect
activeEffect()
activeEffect = null
}
function computed(getter){
let result = ref()
effect(()=>(result.value = getter()))
return result
}
function watch(source, callback) {
let getter;
if (typeof source === 'function') {
getter = source;
} else {
getter = () => source.value;
}
let oldValue, newValue;
const effectFn = () => {
newValue = getter();
if(oldValue !== undefined) callback(newValue, oldValue); // watch第一次不需要执行
oldValue = newValue;
};
effect(effectFn);
}
// 测试用例
const product = reactive({ price: 5, quantity: 2 });
watch(
() => product.price,
(newPrice, oldPrice) => {
console.log(`Price changed from ${oldPrice} to ${newPrice}`);
}
);
const total = ref(1)
watch(total, (newVal, oldVal)=>{
console.log(`Total changed from ${oldVal} to ${newVal}`);
})
product.price = 10; // 应触发 watch 回调并打印 "Price changed from 5 to 10"
product.price = 100
total.value = 2
total.value = 3

View File

@ -0,0 +1,48 @@
import {reactive, ref, computed, watch, effect} from './vue-reactive.js'
// 测试
const product = reactive({ price: 5, quantity: 2 });
const tax = ref(5);
effect(() => {
console.log(`现在的总价是:${product.price * product.quantity}`);
});
// 修改价格
product.price = 10;
// 修改数量
product.quantity = 3;
// 计算含税价格
const total = computed(() => {
return product.price * product.quantity + tax.value;
});
effect(() => {
console.log(`含税价格为:${total.value}`);
});
// 修改税
tax.value = 10;
watch(total, (newVal, oldVal) => {
console.log(`老总价:${oldVal}---->新总价:${newVal}`);
});
watch(
() => product.price,
(newVal, oldVal) => {
console.log(`老价格:${oldVal}---->新价格:${newVal}`);
}
);
watch(
() => product.quantity,
(newVal, oldVal) => {
console.log(`老数量:${oldVal}---->新数量:${newVal}`);
}
);
product.price = 20
product.quantity = 10

View File

@ -0,0 +1,96 @@
const targetMap = new WeakMap(); // 用原始对象作为key依赖映射作为value
let activeEffect = null; // 保存当前的需要订阅通知的effect
function track(target, key) {
if (activeEffect) {
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); // 将efect添加进通知set
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const deps = depsMap.get(key);
deps.forEach((effect) => {
effect();
});
}
export function reactive(target) {
const hander = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
track(target, key);
return result;
},
set(target, key, value, receiver) {
let oldValue = target[key];
let result = Reflect.set(target, key, value, receiver);
if (oldValue !== value) {
trigger(target, key);
}
return result;
},
};
return new Proxy(target, hander);
}
// 创建ref为基本数据类型赋予响应式功能
export function ref(raw) {
const r = {
get value() {
track(r, "value");
return raw;
},
set value(newVal) {
raw = newVal;
trigger(r, "value");
},
};
return r;
}
// 绑定副作用
export function effect(effect) {
activeEffect = effect;
activeEffect();
activeEffect = null;
}
// 计算属性
export function computed(getter) {
let result = ref();
effect(() => (result.value = getter()));
return result;
}
// watch
export function watch(source, callback) {
let getter;
if (typeof source === "function") {
getter = source;
} else {
getter = () => source.value;
}
let oldValue, newValue;
const effectFn = () => {
newValue = getter();
if (oldValue !== undefined) callback(newValue, oldValue); // watch第一次不需要执行
oldValue = newValue;
};
effect(effectFn);
}