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 中的:










