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

news2024/9/18 20:18:34

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()
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/384349.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity常见面试题详解(持续更新...)

一丶声明、定义、实例化、初始化 1、首先我们来讨论在C/C中的声明和定义.. 1)我们先从函数声明和定义说起... 一般我们在C里都会先定义一个函数,然后再Main函数前将函数声明,比如: //函数声明 int Add(int);int Main {} //函数…

tmux终端复用软件

一、安装[rootpool-100-1-1-159 test]# yum install tmux [rootpool-100-1-1-159 test]# yum search tmux Repository extras is listed more than once in the configuration Last metadata expiration check: 0:33:52 ago on Fri 03 Mar 2023 09:10:34 AM CST.Name Exactly M…

【C++】适配器模式 -- stack/queue/dqueue

一、适配器模式 设计模式 设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结;Java 语言非常关注设计模式,而 C 并没有太关注,但是一些常见的设计模式我们还是要学习。 迭代器模式 其实我们在前面学习 strin…

call、apply、bind的区别以及源码实现

首先,需要明确,call()、apply()、bind()这三个方法的作用都是 改变this指向它们之间的不同点在于:call和apply是直接调用的,而bind不会立即调用,需要手动调用(原因在于bind返回的是一个改变了this指向的函数…

请你喝一杯 Corretto?谈一谈 JDK 的新选择

前言如果以20年的时间为限,让我们选出一个影响力最大的程序语言,我的答案应该只有一个 – 那就是 Java。这个1995年诞生的全新的计算机语言,以“一次编写,到处运行”的跨平台特性以及面向对象、泛型编程等现代语言的特性迅速成为了…

Allegro172版本如何通过规则设置检查器件的热平衡问题

Allegro172版本如何通过规则设置检查器件的热平衡问题 在做PCB设计的时候,器件的热平衡问题是必须考虑到的一个设计要点,尤其小封装的阻容器件,热平衡问题没有考虑好,直接影响到装配的可靠性 如下图 小封装器件,一边线宽粗并且铺铜,另外一端是一根细线 Allegro172及以上…

c语言指针怎么理解 第一部分

不理解指针,是因为有人教错了你。 有人告诉你,指针是“指向”某某某的,那就是误导你,给你挖了个坑。初学者小心不要误读这“指向”二字。 第一,“指针”通常用于保存一个地址,这个地址的数据类型在定义指…

ASGCN之依存句法图的构建

文章目录前言1.理论部分1.1 依存句法理论1.2 依存句法分析1.3 依存句法的应用2. 代码实践2.1 数据集2.2 代码实现2.3 效果查看总结前言 本文首先介绍依存句法理论,之后通过代码实现ASGCN中的依存句法图数据的构建。 1.理论部分 1.1 依存句法理论 词与词之间存在主…

Vue3电商项目实战-购物车模块2【04-头部购物车-商品列表-本地、05-头部购物车-删除操作-本地、06-购物车页面-基础布局】

文章目录04-头部购物车-商品列表-本地05-头部购物车-删除操作-本地06-购物车页面-基础布局04-头部购物车-商品列表-本地 目的:根据本地存储的商品获取最新的库存价格和有效状态。 大致步骤: 定义获取最新信息的API定义修改购物车商品信息的mutations定义…

Mybatis工作原理及流程

1、MyBatis介绍 MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和JavaPOJO(PlainOldJavaObjects,普通老式Java对象)为…

OSSFs挂载工具简介

OSSFs挂载工具 OSSFs挂载工具简介 ​ ossfs允许您在Linux系统中将对象存储OSS的存储空间(Bucket)挂载到本地文件系统。挂载完成后,您能够像操作本地文件一样操作OSS的对象(Object),从而实现数据共享。 ​…

RT_Thread Nano 简介, 移植

官网介绍 RT_Thread Nano 1.简介 RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括…

打怪升级之MFC变量小实验

按惯例,这一篇文章主要还是作者读《深入浅出MFC》整理的一些笔记。不过本次还加上了一些作者自己的理解。 实验的前期准备 做实验前,你最好了解一下MFC的执行流程,从winapp到各类控件的实际变化过程,可以参考博主之前的笔记。 …

SOTA!目标检测开源框架YOLOv6 3.0版本来啦

近日,美团视觉智能部发布了 YOLOv6 3.0 版本,再一次将目标检测的综合性能推向新高。YOLOv6-L6 检测精度和速度超越 YOLOv7-E6E,取得当前实时目标检测榜单 SOTA。本文主要介绍了 YOLOv6 3.0 版本中引入的技术创新和优化,希望能为从…

64. 最小路径和

64. 最小路径和 给定一个包含非负整数的 m∗nm * nm∗n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。 示例 1: 输入:grid [[1,3,1],[1,5,1],[…

Hudi的7种索引

1、Bloom Index Bloom Index (default) 使用根据记录键构建的bloom过滤器,也可以使用记录键范围修剪候选文件.原理为计算RecordKey的hash值然后将其存储到bitmap中,为避免hash冲突一般选择计算3次 HoodieKey 主键信息:主要包含recordKey 和p…

[ IFRS 17 ] 新准则下如何确认保险合同

本系列文章:[ IFRS 17 ] 针对保险新准则 IFRS 17 进行一些列文章更新。如若文中如有所疑问或者不同见解,欢迎留言互动交流。 注:本系列文章受众群体较小众,如若对你感到不适,请立刻点击右上角的 【】 本系列文章适用…

RDD持久化原理和共享变量

(一) RDD持久化原理 Spark中有一个非常重要的功能就是可以对RDD进行持久化。当对RDD执行持久化操作时,每个节点都会将自己操作的RDD的partition数据持久化到内存中,并且在之后对该RDD的反复使用中,直接使用内存中缓存…

互联网工程师 1480 道 Java 面试题及答案整理 ( 2023 年 整理版)

最近很多粉丝朋友私信我说:熬过了去年的寒冬却没熬过现在的内卷;打开 Boss 直拒一排已读不回,回的基本都是外包,薪资还给的不高,对技术水平要求也远超从前;感觉 Java 一个初中级岗位有上千人同时竞争&#…

安卓逆向_4 --- 定位关键Smali、monitor使用、log插桩、栈追踪、methodprofiling(方法分析)

1、快速定位关键 smali 代码 1.分析流程 搜索特征字符串 搜索关键api 通过方法名来判断方法的功能 2.快速定位关键代码 反编译 APK 程序,AndroidManifest.xml > 包名/系统版本/组件 程序的主 activity(程序入口界面) 每个…