第四章 reactive对象的简单实现以及reactive的依赖收集和触发依赖

reactive对象的简单实现

主要通过reactive.spec.ts这个测试案例来实现功能

import { reactive } from "../reactive"

describe('reactive',()=>{
    it('happy path',()=>{
        const original = {foo:1}
        const observed = reactive(original)
        expect(observed).not.toBe(original)
        expect(observed.foo).toBe(1)
    })
})

reactive是通过Proxy对传入对象进行了一层封装,然后通过get,set对传入对象进行进行一系列操作,如依赖收集,触发依赖等。值得注意的是他们的值也同时通过Reflect的get和set来进行了获取和设置。
代码如下:

import { track, trigger } from "./effect"

export function reactive(raw){

    return new Proxy(raw,{
        get(target,key){
            const res = Reflect.get(target,key)

            track(target,key)
            return res
        },
        set(target,key,value){
            const res = Reflect.set(target,key,value)

            trigger(target,key)
            return res
        }
    })
}

下面我也将对track依赖收集和trigger触发依赖进行详细讲解

reactive的依赖收集和触发依赖

主要通过effect.spec.ts这个测试案例来实现功能

import { reactive } from "../reactive"
import { effect } from "../effect"

describe('effect',()=>{
    it('happy path',()=>{
        const user = reactive({
            age:10
        })

        let nextAge
        effect(()=>{
            nextAge = user.age+1
        })

        expect(nextAge).toBe(11)

        user.age++
        expect(nextAge).toBe(12)
    })
})

其实主要user.age++后的这个expect的通过就需要到对依赖的收集和触发

依赖收集

依赖收集主要在Proxy中的get函数中通过track实现,而我们选择在effect.ts中导出track函数,我个人觉得effect中也比较好处理,对于effect实例这些变量的获取上都是比较方便的。

依赖收集中最重要的其实就是看明白这个关系: target -> key -> dep,以及理解targetMap,depsMap,dp这三个变量的关系,如果这两个理解了就不会太难了。

首先附上一张图依赖收集和触发依赖的一张图,有助于理解这些关系和他们整个流程:

image.png
由图可见,dep中存储的依赖就是effect中的回调函数fn。(因此为了fn不会重复加入,所以使用了set集合)

接下来就解释一下这几个变量的意思:

首先target -> key -> dep链条的就是他们层层的依赖关系

targetMap:以target为键depsMap为值的Map集合

depsMap::以key为键dep为值的Map集合

dep:是存储fn的set集合

存储关系如图所示:

image.png

依赖收集的代码如下:

const targetMap = new Map()
export function track(target,key){
    // target -> key -> dep
     let depsMap = targetMap.get(target)
     if(!depsMap){
        depsMap = new Map()
        // 没有depsMap时要加进去
        targetMap.set(target,depsMap)
     }


    let dep = depsMap.get(key)
    if(!dep){
        dep = new Set()
        depsMap.set(key,dep)
    }
    dep.add(activeEffect)
}

接下来就说下activeEffect是哪里来的,接下来先附上ReactiveEffect类的代码

let activeEffect
class ReactiveEffect {
    private _fn: any

    constructor(fn){
        this._fn = fn
    }

    run(){
        // 依赖收集之前去给激活的effect赋值
        activeEffect = this
        this._fn()
    }
}

这段代码就可以看出activeEffect是effect.ts中声明的一个全局变量,然后当运行run函数的时候给他赋值为当前的激活的effect。

触发依赖

依赖收集做好了,起触发依赖就很简单了,就跟着上面的存储关系图,用targetMap找到dep容器,然后循环调用里面effect中run方法就可以了。

代码如下:

export function trigger(target,key){
    const depsMap = targetMap.get(target)
    const dep = depsMap.get(key)
    for (const effect of dep) {
        effect.run()
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值