当前位置:主页 > 网页前端 > vue >

一文带你了解vue3.0响应式

时间:2022-09-10 09:19:36 | 栏目:vue | 点击:

我们知道Vue 2.0是利用Ojbect.defineProperty对对象的已有属性值的读取和修改进行劫持,但是这个API不能监听对象属性的新增和删除,此外为了深度劫持对象的内部属性,必须在初始化的时候对内部属性进行递归调用Ojbect.defineProperty,这就造成了一个性能上的消耗。为了解决这些问题,Vue 3.0利用Proxy重写了响应式逻辑并且优化了相关性能。

使用案例

我们先来个示例看下Vue 3.0的响应式API的写法:

案例

changePerson能改变响应式数据person的值,person值的变化会触发组件重新渲染而更新DOM

这里我们可以看到Vue 3.0的使用中,开发者利用reactive函数自己去确定哪些数据为响应式数据,这样就可以避免一些不必要的响应式的性能消耗。例如案例中我们就不需要让nowIndex成为响应式数据。(当然Vue 2.0也可以在data函数外定义数据,这样也是非响应式数据)

我们接下来看看reactive函数的实现原理!

reactive API相关的流程

 reactive

reactive

代码说明:

createReactiveObject 创建响应式对象

createReactiveObject

代码说明:

1.target没有被执行过markRaw方法,或者说target对象没有__v_skip属性值或者__v_skip属性的值为false

2.target不能是不可扩展对象,即target没有被执行过preventExtensions,sealfreeze这些方法;

3.targetObject或者Array;

4.targetMap,Set,WeakMap,WeakSet

1.Object或者Array的处理函数是collectionHandlers;

2.Map,Set,WeakMap,WeakSet的处理函数是baseHandlers;

mutableHandlers 处理函数

mutableHandlers

我们知道访问对象属性会触发get函数,设置对象属性会触发set函数,删除对象属性会触发deleteProperty函数,in操作符会触发has函数,getOwnPropertyNames会触发ownKeys函数。我们接下来看看你这几个函数的代码逻辑。

get函数

由于没有传参,isReadonlyshallow都是默认参数false。

get

代码逻辑

get函数的的调用时机

回答这个问题前我们需要回到前面一篇关于setup的文章―揭开Vue3.0 setup函数的神秘面纱

setupStatefulComponent

handleSetupResult

ctx

render

总结:组件实例对象执行render函数生成子树VNode时,会调用响应式对象的get函数。

track 收集依赖

我们上面的get函数的代码解释中两次提到了收集依赖,那什么是收集依赖呢?
要实现响应式,就是当数据变化后会自动实现一些功能,比如执行某些函数等。因为副作用渲染函数能触发组件的重新渲染而更新DOM,所以这里收集的依赖就是当数据变化后需要执行的副作用渲染函数

也就是说,当执行get函数时就会收集对应组件的副作用渲染函数

track

tractEffect

我们可以拿我们的例子说明最后的结果:

结果

set函数

set

代码逻辑:

trigger 分发依赖

trigger

trigger 代码逻辑很清晰,就是从get函数中收集来的依赖targetMap中找到对应的函数,然后执行这些副作用渲染函数,更新DOM。

get和副作用渲染函数关联

我们回过头来再解答一个疑问:就是从get函数中收集来的副作用渲染函数是怎么确定的,即访问person.name时如何确定关联哪个副作用渲染函数呢?

我们接下来一步步梳理其中的逻辑:

mountComponent

setupRenderEffect

ReactiveEffect

componentUpdateFn

tractEffects

这里设计一个栈的结构,主要是为了解决effect嵌套的问题。

副作用渲染函数的执行过滤

如果仔细思考下可能会有一个疑问?name,age,address都修改了,然后他们都关联了同一个渲染函数,理论上同时修改这三个值会触发三次组件重新渲染呢,这明显是不合理的。那Vue是如何控制只执行一次呢?

ReactiveEffect

在这里插入图片描述

queueJob

结尾

本文详细介绍了Vue3.0的相应式原理:利用Proxy劫持对象,访问对象的时候会触发get方法,此时会进行依赖的收集;当修改对象数据的时候会触发set方法,此时会派发依赖,即调用组件的副作用渲染函数(其实不限于), 这样组件就能重新渲染,DOM更新。

您可能感兴趣的文章:

相关文章