Vue3.0生命周期

731 阅读1分钟

注册钩子函数

const createHook = (lifecycle) => (hook, target = currentInstance) => 
// post-create lifecycle registrations are noops during SSR (except for serverPrefetch)
(!isInSSRComponentSetup || lifecycle === "sp" /* SERVER_PREFETCH */) &&
    injectHook(lifecycle, hook, target);
const onBeforeMount = createHook("bm" /* BEFORE_MOUNT */);
const onMounted = createHook("m" /* MOUNTED */);
const onBeforeUpdate = createHook("bu" /* BEFORE_UPDATE */);
const onUpdated = createHook("u" /* UPDATED */);
const onBeforeUnmount = createHook("bum" /* BEFORE_UNMOUNT */);
const onUnmounted = createHook("um" /* UNMOUNTED */);
const onServerPrefetch = createHook("sp" /* SERVER_PREFETCH */);
const onRenderTriggered = createHook("rtg" /* RENDER_TRIGGERED */);
const onRenderTracked = createHook("rtc" /* RENDER_TRACKED */);
function onErrorCaptured(hook, target = currentInstance) {
    injectHook("ec" /* ERROR_CAPTURED */, hook, target);
}

injected函数实现如下

function injectHook(type, hook, target = currentInstance, prepend = false) { 
  const hooks = target[type] || (target[type] = []) 
  // 封装 hook 钩子函数并缓存 
  const wrappedHook = hook.__weh || 
    (hook.__weh = (...args) => { 
      if (target.isUnmounted) { 
        return 
      } 
      // 停止依赖收集 
      pauseTracking() 
      // 设置 target 为当前运行的组件实例 
      setCurrentInstance(target) 
      // 执行钩子函数 
      // callWithAsyncErrorHandling方法执行注册的hook钩子函数, 执行完毕后设置当前运行组件实例为null, 并恢复依赖收集
      const res = callWithAsyncErrorHandling(hook, target, type, args) 
      setCurrentInstance(null) 
      // 恢复依赖收集 
      resetTracking() 
      return res 
    }) 
  if (prepend) { 
    hooks.unshift(wrappedHook) 
  } 
  else { 
    hooks.push(wrappedHook) 
  } 
}

执行顺序

function registerLifecycleHook(register, hook) {
  if (isArray(hook)) {
    hook.forEach(_hook => register(_hook.bind(publicThis)));
  }
  else if (hook) {
    register(hook.bind(publicThis));
  }
}
registerLifecycleHook(onBeforeMount, beforeMount);
registerLifecycleHook(onMounted, mounted);
registerLifecycleHook(onBeforeUpdate, beforeUpdate);
registerLifecycleHook(onUpdated, updated);
registerLifecycleHook(onActivated, activated);
registerLifecycleHook(onDeactivated, deactivated);
registerLifecycleHook(onErrorCaptured, errorCaptured);
registerLifecycleHook(onRenderTracked, renderTracked);
registerLifecycleHook(onRenderTriggered, renderTriggered);
registerLifecycleHook(onBeforeUnmount, beforeUnmount);
registerLifecycleHook(onUnmounted, unmounted);
registerLifecycleHook(onServerPrefetch, serverPrefetch);

onBeforeUpdate 和 onUpdated

onBeforeUpdate注册的beforeUpdate会在组件更新之前执行, onUpdated会在组件更新之后执行.

不要在 updated 钩子函数中更改数据,因为这样会再次触发组件更新,导致无限递归更新

父组件的更新不一定会导致子组件的更新,因为 Vue.js 的更新粒度是组件级别的

onBeforeUnmount 和 onUnmounted

onBeforeUnmount 注册的 beforeUnMount 钩子函数会在组件销毁之前执行

onUnmounted 注册的 unmounted 钩子函数会在组件销毁之后执行

const unmountComponent = (instance, parentSuspense, doRemove) => { 
  const { bum, effects, update, subTree, um } = instance 
  // 执行 beforeUnmount 钩子函数 
  if (bum) { 
    invokeArrayFns(bum) 
  } 
  // 清理组件引用的 effects 副作用函数 
  if (effects) { 
    for (let i = 0; i < effects.length; i++) { 
      stop(effects[i]) 
    } 
  } 
  // 如果一个异步组件在加载前就销毁了,则不会注册副作用渲染函数 
  if (update) { 
    stop(update) 
    // 调用 unmount 销毁子树 
    unmount(subTree, instance, parentSuspense, doRemove) 
  } 
  // 执行 unmounted 钩子函数 
  if (um) { 
    queuePostRenderEffect(um, parentSuspense) 
  } 
}

function stop(effect) {
    if (effect.active) {
        cleanup(effect);
        if (effect.options.onStop) {
            effect.options.onStop();
        }
        effect.active = false;
    }
}

onErrorCaptured

组件销毁的逻辑比较简单, 就是清理组件实例上绑定的effect副作用函数和注册的副作用渲染函数update以及调用unmount销毁子树.

函数会从当前宝座的组件的父组件实例开始, 尝试去查找注册errorCaptured钩子函数, 如果有则遍历判断errorCaptured钩子函数是否为true, 如果是则说明这个错误已经正确处理, 否则会通过logError向控制台抛出错误.

onRenderTracked 状态跟踪

onRenderTracked直译过来就是状态跟踪,它会跟踪页面上所有响应式变量和方法的状态,也就是我们用return返回去的值,它都会跟踪。只要页面有update的情况,它就会跟踪,然后生成一个event对象,我们通过event对象来查找程序的问题所在。

onRenderTriggered 状态触发

onRenderTriggered直译过来是状态触发,它不会跟踪每一个值,而是给你变化值的信息,并且新值和旧值都会给你明确的展示出来。

如果把onRenderTracked比喻成散弹枪,每个值都进行跟踪,那onRenderTriggered就是狙击枪,只精确跟踪发生变化的值,进行针对性调试。

对 event 对象属性的详细介绍:

  • key 那边变量发生了变化
  • newValue 更新后变量的值
  • oldValue 更新前变量的值
  • target 目前页面中的响应变量和函数

参考链接:blog.csdn.net/newway007/a…