运行带有副作用的render函数

  1. const setupRenderEffect = (
  2. instance,
  3. initialVNode,
  4. container,
  5. anchor,
  6. parentSuspense,
  7. isSVG,
  8. optimized
  9. ) => {
  10. instance.update = effect(function componentEffect() {
  11. if (!instance.isMounted) {
  12. let vnodeHook
  13. const { el, props } = initialVNode
  14. const { bm, m, parent } = instance
  15. // beforeMount hook 执行beforeMount(挂载之前)钩子函数,是个数组。
  16. if (bm) {
  17. invokeArrayFns(bm)
  18. }
  19. // 生成子树结构,创建组件的vnode
  20. // 执行组件内部的render函数 (手写或template编译生成) 生成渲染vnode,渲染vnode就是组件实际要渲染出来的
  21. // 内容对应的vnode,并将渲染vnode存储到组件实例上
  22. // 注意:执行render函数会访问组件实例上的响应式数据,从而触发依赖收集,当前定义的renderEffect会被收集到依赖仓库
  23. // 当后续发生数据变化时,renderEffect则会被派发,触发re-render
  24. const subTree = (instance.subTree = renderComponentRoot(instance))
  25. if (el && hydrateNode) {
  26. } else {
  27. // 将子树渲染到container中
  28. patch(
  29. null,
  30. subTree,
  31. container,
  32. anchor,
  33. instance,
  34. parentSuspense,
  35. isSVG
  36. )
  37. initialVNode.el = subTree.el
  38. }
  39. // mounted hook
  40. // 执行mount(挂载之后)钩子函数
  41. if (m) {
  42. queuePostRenderEffect(m, parentSuspense)
  43. }
  44. instance.isMounted = true
  45. initialVNode = container = anchor = null
  46. } else {
  47. // updateComponent 更新组件,非首次
  48. let { next, bu, u, parent, vnode } = instance
  49. let originNext = next
  50. let vnodeHook
  51. if (next) {
  52. next.el = vnode.el
  53. updateComponentPreRender(instance, next, optimized)
  54. } else {
  55. next = vnode
  56. }
  57. const nextTree = renderComponentRoot(instance)
  58. const prevTree = instance.subTree
  59. instance.subTree = nextTree
  60. // 把对应的subTree渲染到container中,子树可能是element、text、component等
  61. patch(
  62. prevTree,
  63. nextTree,
  64. // parent may have changed if it's in a teleport
  65. hostParentNode(prevTree.el),
  66. // anchor may have changed if it's in a fragment
  67. getNextHostNode(prevTree),
  68. instance,
  69. parentSuspense,
  70. isSVG
  71. )
  72. next.el = nextTree.el
  73. }
  74. }, createDevEffectOptions(instance))
  75. }

总结

该方法只要是实现 instance.update 方法,这个方法其实就是一个 effect

  • 在没有传入options.lazy时,会默认执行一次;
  • 触发effect的get,然后收集当前的componentEffect,当数据有变化时,会执行trigger
  • 当配置 schedulerqueueJob时,会放入全局队列queue中等待nextTick运行,因此多个状态会合并在一起并更新视图

主要做了3件事:

  1. 更新组件VNode节点
  2. 渲染子树VNode
  3. 根据新旧子VNode,执行 patch