【vue3学习笔记】01.响应式模块(reactive,effect,ReactiveEffect)

一、响应式模块的作用

响应式模块是vue框架最核心的功能,vue中的watch、computed、模板更新都是基于响应式模块实现的。
响应式模块可以做到响应式对象中的某些属性发生变化时,自动执行这些属性依赖的函数,实现自动更新

二、响应式模块的组成

响应式模块由reactive响应式对象和ReactiveEffect组成

  1. reactive响应式对象
    通过new Proxy(源对象、控制器)创建响应式对象,访问该对象的所有属性都会调用控制器中的get方法,设置该对象的所有属性都会调用控制器中的set方法。
    调用get方法时,会进行依赖收集
    调用set方法时,会进行依赖更新

  2. ReactiveEffect 类

作用:把用户传进来的逻辑封装起来,在合适的时机(响应式数据更新时)去调用。

参数:
1.fn:调用的时候会收集依赖(为了解决函数中的分支问题,收集依赖之前会做一次清理操作,把之前收集的依赖先清理掉)。
2.scheduler: (响应式数据更新时)去调用,如果没传这个参数会调用fn。
属性:
1.fn: 用户创建实例的时候传进来的函数
2.scheduler: 用户创建实例的时候传进来的调度函数
3.active:Boolean 标记当前ReactiveEffect对象是否激活状态,如果不是激活状态不会进行依赖收集(默认激活)
4.parent:(null或ReactiveEffect对象) 记录嵌套的effect中的上一级
5.deps:Array 记录当前ReactiveEffect对象在哪里被收集过(属性收集的依赖会使用一个set集合存储,deps这个属性就是用来存储包含当前ReactiveEffect对象的集合的地址)。清除依赖的时候会将当前的ReactiveEffect对象从deps里面的所有集合中删除。
方法:
1.run: 执行用户传进来的fn。
代码:

run() {
    if (!this.active) {
      return this.fn();
    } //  如果当前是未激活状态 不进行依赖收集

    try {
      //  这里需要进行依赖收集 ,将当前的effect和稍后用到的属性关联起来

      this.parent = activeEffect; //  记录上一级effect,第一次为null
      activeEffect = this;

      //  执行函数之前先清理effect,再重新收集  解决分支问题
      cleanupEffect(this);
      return this.fn();
    } finally {
      activeEffect = this.parent;
      this.parent = null;
    }
  }

这个函数要做的事情:
①判断this.active是否等于false :如果是说明当前的effect不是激活状态,不需要进行依赖收集:直接调用this.fn()并retun,不往下执行
②this.parent指向全局变量activeEffect(如果当前ReactiveEffect对象调用run方法时是在其他ReactiveEffect对象的run方法中执行的,this.parent就会记录上一级的ReactiveEffect对象。等到依赖收集完成(也就是调用完this.fn)之后全局变量activeEffect指向this.parent。解决了effect嵌套问题);
③activeEffect指向this(下一步调用this.fn时,相关属性会收集activeEffect作为依赖)
④调用this.fn (此时如果在这个函数中访问了某个响应式对象的某些属性,就会调用这个响应式对象中预先设置好的get函数,这时候就会在get函数中进行依赖收集)
⑤activeEffect指向this.parent
⑥this.parent指向null(这一步其实可以不做,因为下次调用run会对this.parent重新赋值)

  1. effect函数

作用:创建一个ReactiveEffect实例,返回一个可以直接执行当前ReactiveEffect实例中的run方法的函数(这个函数一般用来手动触发更新)。默认先执行一次ReactiveEffect实例的run方法进行依赖收集,如果依赖属性发生变化就会触发更新

参数:
fn: 用户传进来的立即执行函数
option: 对象类型:一般包含scheduler属性(调度函数)

这个函数要做的事情:
① 创建一个ReactiveEffect实例(用一个_effect变量接收)
②执行ReactiveEffect实例的run方法(进行依赖收集)
③定义一个runner函数(this绑定_effect)
④返回runner函数

代码:

export function effect(fn, options: any = {}) {
  //  fn可以根据数据变化重新执行

  const _effect = new ReactiveEffect(fn, options.scheduler);
  _effect.run();

  const runner = _effect.run.bind(_effect);

  runner.effect = runner;

  return runner;
}
  1. 依赖收集

作用: 将某个响应式对象中的某个属性与activeEffect创建关联关系。

存储关联关系的数据结构:
用一个WeakMap映射表存储对象中的某些属性和effect的依赖关系,如下图:
在这里插入图片描述
其中:weakMap中的键代表某个对象,值是一个Map映射表,这个映射表反映该对象某些属性和effect的绑定关系(键代表属性,值代表effect集合)

  1. 触发更新
三、核心原理

使用reacticve创建响应式对象时,会对该对象进行代理并返回一个Proxy代理对象。在创建Proxy对象时,会传入handler对象,handler对象声明了代理对象的get和set等操作。
访问该代理对象的某个属性时,会进入handler中的get函数,

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值