// update props
if (propsData && vm.$options.props) {
toggleObserving(false)
// 注意props被指向了 _props
const props = vm._props
const propKeys = vm.$options._propKeys || [] for (let i = 0; i < propKeys.length; i++) {
const key = propKeys[i] const propOptions: any = vm.$options.props // wtf flow?
// 就是这句话,触发了对于 _props.msg 的依赖更新。
props[key] = validateProp(key, propOptions, propsData, vm)
}
toggleObserving(true)
// keep a copy of raw propsData
vm.$options.propsData = propsData
}
那么,由于上面注释标明的那段代码,msg 的变化通过 _props 的响应式能力,也让子组件重新渲染了,到目前为止,都只有真的用到了 msg 的组件被重新渲染了。
正如官网 api 文档中所说:
vm.$forceUpdate:迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
—— vm-forceUpdate文档
我们需要知道一个小知识点,vm.$forceUpdate 本质上就是触发了渲染watcher的重新执行,和你去修改一个响应式的属性触发更新的原理是一模一样的,它只是帮你调用了 vm._watcher.update()(只是提供给你了一个便捷的api,在设计模式中叫做门面模式)
slot是怎么更新的?
注意这里也提到了一个细节,也就是 插入插槽内容的子组件:
举例来说
假设我们有父组件parent-comp:
<div>
<slot-comp>
<span>{{ msg }}</span>
</slot-comp>
</div>
子组件 slot-comp:
<div>
<slot></slot>
</div>
组件中含有 slot的更新 ,是属于比较特殊的场景。
这里的 msg 属性在进行依赖收集的时候,收集到的是 parent-comp 的`渲染watcher。(至于为什么,你看一下它所在的渲染上下文就懂了。)
那么我们想象 msg 此时更新了,
<div>
<slot-comp>
<span>{{ msg }}</span>
</slot-comp>
</div>
这个组件在更新的时候,遇到了一个子组件 slot-comp,按照 Vue 的精确更新策略来说,子组件是不会重新渲染的。
但是在源码内部,它做了一个判断,在执行 slot-comp 的 prepatch 这个hook的时候,会执行 updateChildComponent 逻辑,在这个函数内部会发现它有 slot 元素。
prepatch (oldVnode: MountedComponentVNode, vnode: MountedComponentVNode) {
const options = vnode.componentOptions
// 注意 这个child就是 slot-comp 组件的 vm 实例,也就是咱们平常用的 this










