〖Vue3 源码笔记05〗Vue3 setupRenderEffect / Vue2 Render Watcher

485 阅读1分钟

mountComponent 最后设置Render Effect(Vue2 Render Watcher

setupRenderEffect(
      instance,
      initialVNode,
      container,
      anchor,
      parentSuspense,
      isSVG,
      optimized
    )

setupRenderEffect

// packages\runtime-core\src\renderer.ts
const setupRenderEffect: SetupRenderEffectFn = (
  instance,
  initialVNode,
  container,
  anchor,
  parentSuspense,
  isSVG,
  optimized
) => {
    instance.update = effect(function componentEffect() {
       let vnodeHook: VNodeHook | null | undefined
       const { el, props } = initialVNode
       const { bm, m, a, parent } = instance
       const subTree = (instance.subTree = renderComponentRoot(instance))
       
       // beforeMount
       if (bm) {
         invokeArrayFns(bm)
       }
       
       // onVnodeBeforeMount
       if ((vnodeHook = props && props.onVnodeBeforeMount)) {
         invokeVNodeHook(vnodeHook, parent, initialVNode)
       }
       
       patch(
            null,
            subTree,
            container,
            anchor,
            instance,
            parentSuspense,
            isSVG
          )
          
       initialVNode.el = subTree.el
       
       // mounted
       if (m) {
         queuePostRenderEffect(m, parentSuspense)
       }
       // onVnodeMounted
       if ((vnodeHook = props && props.onVnodeMounted)) {
         queuePostRenderEffect(() => {
           invokeVNodeHook(vnodeHook!, parent, initialVNode)
         }, parentSuspense)
       }
       
       // activated hook for keep-alive roots.
       if (
         a &&
         initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
       ) {
         queuePostRenderEffect(a, parentSuspense)
       }
       
       instance.isMounted = true
    }, prodEffectOptions)

effect

export function effect<T = any>(
  fn: () => T,
  options: ReactiveEffectOptions = EMPTY_OBJ
): ReactiveEffect<T> {
  if (isEffect(fn)) {
    fn = fn.raw
  }
  const effect = createReactiveEffect(fn, options)
  if (!options.lazy) {
    // 直接运行
    effect()
  }
  return effect
}

function createReactiveEffect<T = any>(
  fn: (...args: any[]) => T,
  options: ReactiveEffectOptions
): ReactiveEffect<T> {
  const effect = function reactiveEffect(...args: unknown[]): unknown {
    if (!effect.active) {
      return options.scheduler ? undefined : fn(...args)
    }
    if (!effectStack.includes(effect)) {
      cleanup(effect)
      try {
        enableTracking()
        effectStack.push(effect)
        activeEffect = effect
        // 直接运行
        return fn(...args)
      } finally {
        effectStack.pop()
        resetTracking()
        activeEffect = effectStack[effectStack.length - 1]
      }
    }
  } as ReactiveEffect
  effect.id = uid++
  effect._isEffect = true
  effect.active = true
  effect.raw = fn
  effect.deps = []
  effect.options = options
  return effect
}