[vue3源码] reactivity包概述(附注释版源码地址)

本文从源码角度探讨Vue3的reactivity包,讲解响应式的基本思路,包括初始化、依赖收集和触发响应的三个阶段。重点分析了reactive和ref的实现原理,以及computed API的运行逻辑,帮助读者深入理解Vue3的响应式系统。
摘要由CSDN通过智能技术生成

前言

从本文开始,我不会再对源码做逐行解释,而是选择以api作为切入点,自顶向下地剖析其原理。 如果读者对源码的细节有兴趣,或者需要查看代码的逐行解析则可以参考这个项目(待上传)。这是我对源码加过注释的版本,注释几乎覆盖每一行代码,不仅有对源码的解释也有我自己当时的所感所想。

阅读本文前可以先阅读以下内容:

如果你暂时没有耐心阅读这些文章的话,不妨先开始阅读下面的正文,遇到相关知识再针对性地阅读它们也是一种好办法。

reactivity包是阅读源码的一个好开始

在vue3中,一切与响应式相关的代码都被写进了名为reactivity的包里。响应式是vue代替我们完成视图更新的手段,是vue的核心能力。学习这部分知识有助于我们更深刻的理解平时常用的api。不仅如此,由于reactivity完全不依赖于其他几个包,它甚至可以独立于vue存在,因此在阅读过程中可以将注意力全部放在这个包本身。另外,截止到文章发布前,vue3仍处于测试阶段,每天master分支都会有更新,但是reactivity包几乎没有过改动。基于上述三个理由,我认为从reactivity包开始阅读源码是一个好的选择。

Vue响应式基本思路

在使用vue的过程中我们发现无论是number、string、boolean、undefined、null、object还是Symbol,都可以被ref api转化为响应式对象,这是怎么实现的?reactive和ref究竟有什么区别? 副作用是如何被管理的? 本节内容就涵盖了上述问题的答案。

将响应式逻辑分为三个阶段更有助于理解

整个响应式的出场“人物”就两个,一个是响应式对象,通常也称为依赖。 另一个是副作用(effect)。一个响应式对象可以关联多个副作用,一个副作用也可以关联多个响应式对象,两者是多对多的关系。响应式这个庞杂的过程,就是以这两个角色作为主角展开的。

注意:在理解响应式对象和副作用的时候请暂且忽略computed,我稍后会单独提到它。因为它比较特殊——它的实例同时包含了effect和依赖,更新逻辑也与一般的响应式对象不同。

初始化

首先进行的是响应式对象的初始化工作,有两类api可以将一个值改造为响应式对象,分别是reactive(及readonly和shallowReactive)和ref。区别在于,reactive api改造的目标(target),只能是对象,而ref则接受任何类型的值。例如,如果我们尝试执行:

reactive(1)

在开发环境下会提示:value cannot be made reactive: 1

把1替换成对象外的任何一种类型的都是如此。

reactive和ref的这个差别是由于它们实现原理的不同引起的。下面分别解释一下两者的原理——同时这也是初始化过程。

对一个对象调用reactive其实是利用proxy对这个对象设置了get和set。在set中会调用trigger方法找到全部相关的effect,然后依次执行。在get中会调用track方法将effect和自身进行关联。而最后创建出的全部proxy都会被存储在全局的readonlyMap或reactiveMap中。

而对一个值调用ref则不同,vue会创建一个RefImpl类的实例,值会被保存在名为_value的属性内,并设置存值函数(set value)和取值函数(get value),同样是在set中调用trigger方法,以及在get中调用track方法。

我们通常使用ref将基本类型的值改造为响应式对象,而用reactive处理对象。

由此可以知道,reactive和ref其实是实现响应式的两种思路,ref通过将参数包裹成refImpl实例,通过存取器实现响应式。而reactive则是在target外架设一层proxy,然后把proxy返回给用户,用户之后的所有操作都要经由proxy处理,而响应式的能力就在proxy的get和set中被实现。

上述提到的proxy以及RefImpl类的实例都称为响应式对象,因为用户对它们的值的存取操作能够被vue拦截以便触发后续的动作。

依赖收集

我们知道当响应式对象的值发生变化时会执行effect,那么两者之间就必须先建立映射关系。 也就是说,vue必须能够通过响应式对象找到那些访问了(使用了)此对象的effect,并重新执行它们。上一步的状态初始化完成后,就可以和effect建立映射关系了,建立映射关系的过程就叫做依赖收集。在大多数情况下,首次依赖收集是在effect初始化过程中完成的。 既然依赖收集的最终目的是将响应式对象和effect关联起来。那么如何关联呢?vue是通过这样一个结构来实现的:

在这里插入图片描述

targetMap是WeakMap类型,KeyToDepMap是map类型,而dep是set类型。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值