eltree ref什么时候有_Vue3响应式系统源码解析-Ref篇

文章转载自:https://zhuanlan.zhihu.com/p/85978064

我们阅读源码的原因是什么?无非是1:学习;2:更好的使用这个库。如果只是想大致的了解下原理,倒不必花时间阅读源码,几句话,几张图就能搞清楚,网上搜搜应该就有很多。因此,阅读源码的过程一定是要对不明白的地方深入了解,肯定是很费时间的。

在这过程中,有些知识点,跟库本身可能没什么关系,但如果不懂,又难继续理解。对于这些知识点,我会尽量少的解释,但会贴上尽量完善的文档,方便不了解的同学先阅读学习。

f40dfce4e968aa88e5be58b3dbe25ee8.png

前言

在上篇文章中说道,ref是最影响源码阅读的文件。但如果不先搞明白它,看其他的只会更晕。我先帮大家理清ref的逻辑跟概念。

由于现在(2019/10/9)vue@3还未正式发版,大家还不熟悉其相关的用法。上篇文章虽然介绍了不少,但其实还是有不少疑问。在阅读本篇文章之前,如果有时间,建议先阅读Vue官方对Composition API的介绍: 1. Vue Composition API 2. Ref Vs Reactive

读完关于Composition API的介绍,会对了解本库有更多认识,便于更好的理解源码。

ref跟reactive是整个源码中的核心,通过这两个方法创建了响应式数据。要想完全吃透reactivity,必须先吃透这两个。

Ref

ref最重要的作用,其实是提供了一套Ref类型,我们先来看,它到底是个怎么样的数据类型。(为了更好的做解释,我会调整源码中的接口、类型、函数等声明顺序,并会增加一些注释方便阅读)

62e5f083699990d19fe77096691648a0.png

要想了解UnwrapNestedRefs与UnwrapRef,必须先要了解ts中的infer。如果之前不了解,请先阅读相关文档。看完文档,再建议去google一些案例看看加深下印象。

现在我们假设你了解了infer概念,也了解了它的日常用法。再来看源码:

bb352ff88b2f88521abbe6b03bf10cda.png

如果还是懵,建议后续再去看看infer的相关介绍。在这我们直接抛结果:

Ref是这样的一种数据结构:它有个key为Symbol的属性做类型标识,有个属性value用来存储数据。这个数据可以是任意的类型,唯独不能是被嵌套了Ref类型的类型。 具体来说就是不能是这样 Array 或者这样 { [key]: Ref }。但很奇怪的是,这样Ref 又是可以的。具体为什么也不知道,所以我勇敢地提了个PR...

(果然Ref 是不够完美的,2019.10.10晚,我这PR被合并了。大家遇到疑问时,也可以勇敢的提PR,说不定就被合了....)

另外,Map、Set、WeakMap、WeakSet也是不支持解套的。说明Ref数据的value也有可能是Map这样的数据类型。

说回Ref,从上篇文章中,我们已经了解到,Ref类型的数据,是一种响应式的数据。然后我们看其具体实现:

b4f120eebc48ea085336071fdbef57e3.png

其实最难理解的就在于这个ref函数。我们看到,这里也定义了get/set,却没有任何Proxy相关的操作。在之前的信息中我们知道reactive能构建出响应式数据,但要求传参必须是对象。但ref的入参是对象时,同样也需要reactive做转化。那ref这个函数的目的到底是什么呢?为什么需要有它?

在文章开头,我贴了这份官方介绍Ref vs Reactive,这其中其实已经说的很明白。

However, the problem with going reactive-only is that the consumer of a composition function must keep the reference to the returned object at all times in order to retain reactivity. The object cannot be destructured or spread:

对于基本数据类型,函数传递或者对象解构时,会丢失原始数据的引用,换言之,我们没法让基本数据类型,或者解构后的变量(如果它的值也是基本数据类型的话),成为响应式的数据。

// 我们是永远没办法让`a`或`x`这样的基本数据成为响应式的数据的,Proxy也无法劫持基本数据。const a = 1;const { x: 1 } = { x: 1 }

但是有时候,我们确实就是想一个数字、一个字符串是响应式的,或者就是想利用解构的写法。那怎么办呢?只能通过创建一个对象,也即是源码中的Ref数据,然后将原始数据保存在Ref的属性value当中,再将它的引用返回给使用者。既然是我们自己创造出来的对象,也就没必要使用Proxy再做代理了,直接劫持这个value的get/set即可,这就是ref函数与Ref类型的由来。

不过单靠ref还没法解决对象解构的问题,它只是将基本数据保持在一个对象的value中,以实现数据响应式。对于对象的解构还需要另外一个函数:toRefs。

f197e48bbce1f1cf91f5ed1076b912f8.png

通过遍历对象,将每个属性值都转成Ref数据,这样解构出来的还是Ref数据,自然就保持了响应式数据的引用。但是源码中有一点要注意,toRefs函数中引用的是toProxyRef而不是ref,它并不会在get/set中注入track跟trigger,也就是说,向toRefs传入一个正常的对象,是不会返回一个响应式的数据的。必须要传递一个已经被reactive执行返回的对象才能有响应式的效果。感觉这点可以优化,暂时也不知道小右这样做的原因是什么。由于这里会牵扯到track跟trigger,而这两个在我写本文时还没研究,就没胆子提PR了。

到这,我们就把ref的源码给看完了。

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

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

相关文章

揭秘.NET Core剪裁器背后的技术

十天前,我发布了对.NET Core程序进行瘦身的开源软件Zack.DotNetTrimmer,与.NET Core内置的剪裁器相比,Zack.DotNetTrimmer不仅对程序的剪裁效果更好,而且还支持WPF、WinForm程序。很多朋友对于这个开源项目的原理很感兴趣&#xf…

C和指针之动态内存分配之编程练习3

1、问题 编写一个函数,从标准输入读取一个字符串,把字符串复制到动态内存分配的内存中,并返回该字符串的拷贝,这个函数不应该对读入字符串的长度作任何限制! 2、代码实现 #include <stdio.h> #include <stdlib.h>#define OFFSET 5char *my_strcpy…

freetds 移植

移植freetds主要是为了能够在linux下&#xff0c;使用C语言访问微软的sqlserver数据库。 参考连接 http://blog.csdn.net/neighbor1000/article/details/8824084 http://blog.csdn.net/lovehere33/article/details/41118405 在ubuntu上安装 从官网下载最新的稳定版本。 http://…

优秀程序员的 18 大法则【转载】

DRY原则 不要重复&#xff08;Don’t repeat yourself&#xff09;——程序设计中一个最根本的原则就是要避免重复。许多编程结构&#xff08;比如循环、函数、类等&#xff09;的存在就是为了避免重复。一旦重复&#xff08;例如&#xff0c;一个长表达式&#xff0c;一系列语…

java邮件系统(java邮件收发系统源代码和下载地址)

2019独角兽企业重金招聘Python工程师标准>>> 本软件包包括源文件和可执行的jar文件 项目下载地址&#xff1a; 下载 1. 运行方式 A可以直接运行jar文件&#xff08;电脑上必须安装jdk1.6而且关联jar文件&#xff09; B可以用eclipse导入源文件然后运行 2功能简介…

两对光纤收发器用网线连接_为什么现在的人不喜欢用网线,反而更爱用光纤来传输呢?涨知识了...

随着通信技术的不断发展&#xff0c;信号传输介质已从原来的同轴电缆逐渐变为光纤。光纤传输完全满足大容量数据通信正确&#xff0c;可靠&#xff0c;高速传输和处理的要求&#xff0c;已成为世界上主要的通信方式。本文主要详细介绍光纤传输的基本知识&#xff0c;希望对您有…

openGauss学习笔记-170 openGauss 数据库运维-备份与恢复-导入数据-更新表中数据-使用合并方式更新和插入数据

文章目录 openGauss学习笔记-170 openGauss 数据库运维-备份与恢复-导入数据-更新表中数据-使用合并方式更新和插入数据170.1 前提条件170.2 操作步骤 openGauss学习笔记-170 openGauss 数据库运维-备份与恢复-导入数据-更新表中数据-使用合并方式更新和插入数据 在用户需要将…

C和指针之动态内存分配之编程练习4

1、问题 4.编写一个程序&#xff0c;按照下图中的样子创建数据结构&#xff0c;最后三个对象都是动态分配的结构。第一个对象则可能是一个静态的指向结构的指针。你不必使这个程序过于全面--我们将在下一章讨论这个结构。 2、代码实现 #include <stdio.h> #include <s…

.NET 6 攻略大全(四)

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;15分钟)接上篇内容&#xff0c;本篇文章将介绍&#xff1a;DependentHandle 现已公开、RyuJIT、即用型代码/Crossgen 2、.NET 诊断&#xff1a;EventPipe、SDK 的相关攻略。 DependentHandle 现已公开该 DependentHan…

[原创]同一个Tomcat,配置多个context、多个Host

需求前提&#xff1a; 系统结束后&#xff0c;需要部署到服务器上。 目前只可以映射到一个固定IP的非80端口。 而server端和web端都要暴露到外网。 所以配置两个context&#xff0c;使得client应用不需要添加服务名&#xff0c;直接使用IP即可访问&#xff1b;server可以通过ht…

[No000022]他们说:得诺贝尔奖到底有多难?

转载于:https://www.cnblogs.com/Chary/p/No000022.html

java操作redis简单学习3

2019独角兽企业重金招聘Python工程师标准>>> package com.hanchao.testredis;import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Set;import redis.clients.jedis.Jedis;import com.alibaba.fastjson.JSON; import com.al…

Xamarin效果第三篇之手机底部弹窗

前面一篇文章把基本的大框架搞定了,这不再逐个去实现里面的细节;今天主要是分享点击了CollectionView内的点点点然后从手机底部弹出一个可以交互的窗口;直接看看最终实现的效果:作为初来乍到的小萌新只能求助万能的群友让大佬们给指条光明通畅的大道,不然容易跑偏;最终给的方向…

自定义sql_一个简单易用的开源BI软件,专为SQL用户设计的开源库

poli一个易于使用的SQL报告应用程序&#xff0c;专为SQL爱好者而设计。SQL中的电源数据分析&#xff0c;可获得更快的业务洞察力。特性⚡️ 自托管和轻松设置平台独立的Web应用程序 单个JAR文件单个SQLite DB文件。在5分钟内启动并运行。连接任何支持JDBC驱动程序的数据库Postg…

Android之ndk编译出现这个错误error: unused variable ‘a‘ [-Werror=unused-variable]

1、问题 在jni里面就加了一行代码 编译的时候出现这个错误 error: unused variable a [-Werrorunused-variable] 2、解决办法 找到相应的Makefile文件 LOCAL_CFLAGS -Wall -Werror 去掉上面的 -Werror&#xff0c;改成如下 LOCAL_CFLAGS -Wall 就可以了

ELK 中的elasticsearch 集群的部署

本文内容 背景ES集群中第一个master节点ES slave节点本文总结 Elasticsearch&#xff08;以下简称ES&#xff09;搭建集群的经验。以 Elasticsearch-rtf-2.2.1 版本为例。 我搭过三个集群&#xff1a;研究ELK时搭了一个&#xff1b;测试环境搭了一个&#xff1b;生产环境搭了一…

Group Box组合框的简单使用 [大三TJB_708]

http://blog.csdn.net/misskissc/article/details/9317783 Group Box组合框的简单使用 [大三TJB_708] 转载于:https://www.cnblogs.com/chuangyiyuan/p/4885637.html

.NetCore中EF Core为迁移的数据库表统一添加前缀

在项目开发的过程中我们往往需要将项目数据库中的表添加一个统一的前缀。我们为什么要添加表前缀呢&#xff1f;有的可能是公司规定&#xff0c;更多的原因是项目和业务的区分。每个项目针对不同的需求或业务场景&#xff0c;追加相应的标识。当项目到达一定规模后&#xff0c;…

Java对象生命周期

目录 1. 创建阶段(Created)2. 应用阶段(In Use)3. 不可见阶段(Invisible)4. 不可达阶段(Unreachable)5. 收集阶段(Collected)6. 终结阶段7. 对象空间的重新分配1. 创建阶段(Created) 为对象分配存储空间开始构造对象从父类到子类对static成员进行初始化父类成员变量按照顺序初始…

C和指针之动态内存分配常见问题和总结

1、动态内存分配常见问题 1) 结构体成员指针未初始化 2)为指针分配内存太小 3)内存分配成功,但是没初始化 4)内存越界,内存泄漏,free多次或者释放之后没有设置为NULL 2、测试代码 #include <stdio.h> #include <stdlib.h> #inclu…