原理深度解析Vue的响应式更新比React快

2020-06-16 06:51:34易采站长站整理

updateChildComponent(
child,
options.propsData, // updated props
options.listeners, // updated listeners
vnode, // new parent vnode
options.children // new children
)
},

其实看传入的参数也能猜到大概了,就是做了:

更新props(后续详细讲)
更新绑定事件
对于slot做一些更新(后续详细讲)

如果有子节点的话,对子节点进行 diff。

比如这样的场景:


<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<ul>

要对于 ul 中的三个 li 子节点 vnode 利用 diff 算法来更新,本篇略过。

然后到此为止,patchVnode 就结束了,并没有像常规思维中的那样去递归的更新子组件树。

这也就说明了,Vue 的组件更新确实是精确到组件本身的。

如果是子组件呢?

假设列表是这样的:


<ul>
<component>1</component>
<component>2</component>
<component>3</component>
<ul>

那么在diff的过程中,只会对 component 上声明的 props、listeners等属性进行更新,而不会深入到组件内部进行更新。

注意:不会深入到组件内部进行更新!(划重点,这也是本文所说的更新粒度的关键)

props的更新如何触发重渲染?

那么有同学可能要问了,如果不会递归的去对子组件更新,如果我们把 msg 这个响应式元素通过props传给 ChildComponent,此时它怎么更新呢?

首先,在组件初始化 props的时候,会走到 initProps 方法。


const props = vm._props = {}

for (const key in propsOptions) {
// 经过一系列验证props合法性的流程后
const value = validateProp(key, propsOptions, propsData, vm)
// props中的字段也被定义成响应式了
defineReactive(props, key, value)
}

至此为止,是实现了对于 _props 上字段变更的劫持。也就是变成了响应式数据,后面我们做类似于 _props.msg = ‘Changed’ 的操作时(当然我们不会这样做,Vue内部会做),就会触发视图更新。

其实,msg 在传给子组件的时候,会被保存在子组件实例的 _props 上,并且被定义成了响应式属性,而子组件的模板中对于 msg 的访问其实是被代理到 _props.msg 上去的,所以自然也能精确的收集到依赖,只要 ChildComponent 在模板里也读取了这个属性。

这里要注意一个细节,其实父组件发生重渲染的时候,是会重新计算子组件的 props 的,具体是在 updateChildComponent 中的: