运行带有副作用的render函数
const setupRenderEffect = (instance,initialVNode,container,anchor,parentSuspense,isSVG,optimized) => {instance.update = effect(function componentEffect() {if (!instance.isMounted) {let vnodeHookconst { el, props } = initialVNodeconst { bm, m, parent } = instance// beforeMount hook 执行beforeMount(挂载之前)钩子函数,是个数组。if (bm) {invokeArrayFns(bm)}// 生成子树结构,创建组件的vnode// 执行组件内部的render函数 (手写或template编译生成) 生成渲染vnode,渲染vnode就是组件实际要渲染出来的// 内容对应的vnode,并将渲染vnode存储到组件实例上// 注意:执行render函数会访问组件实例上的响应式数据,从而触发依赖收集,当前定义的renderEffect会被收集到依赖仓库// 当后续发生数据变化时,renderEffect则会被派发,触发re-renderconst subTree = (instance.subTree = renderComponentRoot(instance))if (el && hydrateNode) {} else {// 将子树渲染到container中patch(null,subTree,container,anchor,instance,parentSuspense,isSVG)initialVNode.el = subTree.el}// mounted hook// 执行mount(挂载之后)钩子函数if (m) {queuePostRenderEffect(m, parentSuspense)}instance.isMounted = trueinitialVNode = container = anchor = null} else {// updateComponent 更新组件,非首次let { next, bu, u, parent, vnode } = instancelet originNext = nextlet vnodeHookif (next) {next.el = vnode.elupdateComponentPreRender(instance, next, optimized)} else {next = vnode}const nextTree = renderComponentRoot(instance)const prevTree = instance.subTreeinstance.subTree = nextTree// 把对应的subTree渲染到container中,子树可能是element、text、component等patch(prevTree,nextTree,// parent may have changed if it's in a teleporthostParentNode(prevTree.el),// anchor may have changed if it's in a fragmentgetNextHostNode(prevTree),instance,parentSuspense,isSVG)next.el = nextTree.el}}, createDevEffectOptions(instance))}
总结
该方法只要是实现 instance.update 方法,这个方法其实就是一个 effect 。
- 在没有传入
options.lazy时,会默认执行一次; - 触发
effect的get,然后收集当前的componentEffect,当数据有变化时,会执行trigger - 当配置
scheduler为queueJob时,会放入全局队列queue中等待nextTick运行,因此多个状态会合并在一起并更新视图
主要做了3件事:
- 更新组件VNode节点
- 渲染子树VNode
- 根据新旧子VNode,执行
patch
