50行代码,详解实现Vue3.x响应式核心代码,实现reactive,ref,computed

简单实现Vue3.x响应式

实现原理:

  • 用过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写,属性的添加、属性的删除等
  • 通过Reflect (反射) :对被代理对象的属性进行操作

直接上代码

注意:通过Proxy代理实现的响应式,可以在set中,捕捉到对象的设置,

在deleteProperty中捕捉到对象属性的删除,即完成对象响应式操作

const targetMap = new WeakMap() // 保存对象的变量
function track(target,key){
    // 如果此时activeEffect为null则不执行下面
    // 这里判断是为了避免例如console.log(person.name)而触发track
    if(!activeEffect) return 
    let depMap = targetMap.get(target)  // 保存对象属性的变量
    if(!depMap) targetMap.set(target,depMap = new Map())
    let dep = depMap.get(key) // 保存每个属性的依赖
    if(!dep) depMap.set(key,dep = new Set())
    dep.add(activeEffect) // 添加属性依赖函数,每次track时加入
}

function trigger(target,key){
    const depMap = targetMap.get(target)
    const dep = depMap?.get(key)
    if(dep) dep.forEach(item=>item()) // 每次触发属性依赖时更新视图
}

function reactive(target){
    const handler = {
        get(target,key,receiver){
            track(receiver,key)  // 访问时收集依赖
            return Reflect.get(target,key,receiver)
        },
        set(target,key,newValue,receiver){
            Reflect.set(target,key,newValue,receiver)
            trigger(receiver,key)  // 属性变更时,更新视图
        },
        deleteProperty(target,key){
            Reflect.deleteProperty(target,key)
            trigger(target,key) // 删除对应属性的依赖随后更新视图
        }
    }
    return new Proxy(target,handler)
}

// 用来全局保存依赖函数
let activeEffect = null
function effect(fn){
    activeEffect = fn
    activeEffect()
    activeEffect = null  
}

function ref(initValue){
    return reactive({value:initValue})
}

function computed(fn){
    const result = ref()
    effect(()=>{result.value = fn()})
    return result
}

代码测试:

let person = {name:'孙悟空',age:222}
let obj2 = {animal:'迪丽热吗',height:28}
let myself = '' ,myself2 = '' ,myself3 = '',myself4 = ''
const effect1 = ()=>{myself = `我的名字是${person.name}`}
const effect2 = ()=>{myself2 = `我今年二二二${person.age}岁了`}
const effect3 = ()=>{myself3 = `狗狗狗${obj2.animal}岁了`}
const effect4 = ()=>{myself4 = `二二狗狗古${obj2.height}岁了`}

person = reactive(person)
obj2 = reactive(obj2)

effect(effect1)
effect(effect2)
effect(effect3)
effect(effect4)

console.log(myself);
console.log(myself2);
console.log(myself3);
console.log(myself4);

看看输出结果:

image-20220319161544832

直接更改数据,并达到响应式:

let person = {name:'孙悟空',age:222}
let obj2 = {animal:'迪丽热吗',height:28}
let myself = '' ,myself2 = '' ,myself3 = '',myself4 = ''
const effect1 = ()=>{myself = `我的名字是${person.name}`}
const effect2 = ()=>{myself2 = `我今年二二二${person.age}岁了`}
const effect3 = ()=>{myself3 = `狗狗狗${obj2.animal}岁了`}
const effect4 = ()=>{myself4 = `二二狗狗古${obj2.height}岁了`}

person = reactive(person)
obj2 = reactive(obj2)

effect(effect1)
effect(effect2)
effect(effect3)
effect(effect4)

// 直接修改数据,响应式更新视图
person.name = 'cmr' ,person.age = 22 
obj2.animal = '啊啊啊四点九四哦',obj2.height = 78

console.log(myself);
console.log(myself2);
console.log(myself3);
console.log(myself4);

image-20220319161742687

测试ref

// 测试ref
let num = ref(5)
console.log(num.value);
effect(()=>{sum = num.value * 100})
console.log(sum); // 500

测试computed

//测试computed
let num1 = ref(5)
let num2 = ref(8)
let sum1 = computed(() => num1.value * num2.value)
let sum2 = computed(() => sum1.value * 10)

console.log(sum1.value) // 40
console.log(sum2.value) // 400

num1.value = 10

console.log(sum1.value) // 80
console.log(sum2.value) // 800

num2.value = 16

console.log(sum1.value) // 160
console.log(sum2.value) // 1600
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值