vue3认识组件与生命周期(小满zs vue3 笔记十二)

tip0: 调用用下面这两个钩子,收集依赖与触发依赖更新

// 依赖收集,用来调试用
onRenderTracked(e => {
  console.log('------onRenderTracked--', e)
})
// 触发依赖,用来调试用
onRenderTriggered(e => {
  console.log('------onRenderTriggered--', e)
})

  

tip: 1. 组件的认识

*组件基础

  每一个.vue 文件呢都可以充当组件来使用,每一个组件都可以复用,

如下lifeCycle(或helloWorld)充当子组件

在引用时,只需要通过import引入,vue3 不需要注册组件,可以直接使用就可以如下: 
<template>
<!-- 直接在这里使用,不需要通过components再启用-->
<life-cycle></life-cycle>
</template>
<script setup lang="ts">
import lifeCycle from './components/lifeCycle.vue';
</script>

组件生命周期

beforeCreate create setup 语法糖模式是没有这两个生命周期的,是这setup代替
简单来说就是一个组件从创建 到 销毁的 过程 成为生命周期
在我们使用Vue3 组合式API 是没有 beforeCreate 和 created 这两个生命周期的,用setup代替
setup(代替vue2 beforeCreate->created)->beforeMount->mounted->beforeUpdate->updated->beforeUnmount->unmounted

onBeforeMount()

在组件DOM实际渲染安装之前调用。在这一步中,根元素还不存在。

onMounted()

在组件的第一次渲染后调用,该元素现在可用,允许直接DOM访问

onBeforeUpdate()

数据更新时调用,发生在虚拟 DOM 打补丁之前。

onUpdated()

DOM更新后,updated的方法即会调用。

onBeforeUnmount()

在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。

onUnmounted()

卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。

 

 源码: 

在控制台看到的都是这些枚举值
export const enum LifecycleHooks {
BEFORE_CREATE = 'bc',
CREATED = 'c',
BEFORE_MOUNT = 'bm',
MOUNTED = 'm',
BEFORE_UPDATE = 'bu',
UPDATED = 'u',
BEFORE_UNMOUNT = 'bum',
UNMOUNTED = 'um',
DEACTIVATED = 'da',
ACTIVATED = 'a',
RENDER_TRIGGERED = 'rtg',
RENDER_TRACKED = 'rtc',
ERROR_CAPTURED = 'ec',
SERVER_PREFETCH = 'sp'
}

源码解析: 

apiLifecycle.ts/render.ts

核心部分
// 创建hook做个缓存
export function injectHook(
  type: LifecycleHooks,
  hook: Function & { __weh?: Function },
  target: ComponentInternalInstance | null = currentInstance,
  prepend: boolean = false
): Function | undefined {
  if (target) {
    // 如果有hook函数直接返回否则创建一个空数组
    const hooks = target[type] || (target[type] = [])
    // cache the error handling wrapper for injected hooks so the same hook
    // can be properly deduped by the scheduler. "__weh" stands for "with error
    // handling".
    const wrappedHook =
      hook.__weh ||
      (hook.__weh = (...args: unknown[]) => {
        if (target.isUnmounted) {
          return
        }
        // disable tracking inside all lifecycle hooks
        // since they can potentially be called inside effects.
        // 先停止收集避免重复收集依赖
        pauseTracking()
        // Set currentInstance during hook invocation.
        // This assumes the hook does not synchronously trigger other hooks, which
        // can only be false when the user does something really funky.
        // 设置target为当前实例
        setCurrentInstance(target)
        const res = callWithAsyncErrorHandling(hook, target, type, args) // 执行完成钩子
        unsetCurrentInstance() // 清空当前实例
        resetTracking() // 恢复依赖收集
        return res
      })
    if (prepend) {
      hooks.unshift(wrappedHook)
    } else {
      hooks.push(wrappedHook)
    }
    return wrappedHook
  } else if (__DEV__) {
    const apiName = toHandlerKey(ErrorTypeStrings[type].replace(/ hook$/, ''))
    warn(
      `${apiName} is called when there is no active component instance to be ` +
        `associated with. ` +
        `Lifecycle injection APIs can only be used during execution of setup().` +
        (__FEATURE_SUSPENSE__
          ? ` If you are using async setup(), make sure to register lifecycle ` +
            `hooks before the first await statement.`
          : ``)
    )
  }
}
// render.ts调用 
componentUpdateFn 函数里用来更新
没有挂载创建并挂载
创建->render->patch->hook执行副作用函数->mounted
否则已经挂载了就更新
更新钩子-> 更新之前beforeUpdate -> render -> patch-> 执行更新hook副作用函数->updated
unmountComponent 销毁函数
执行函数beforeUnmount-> 卸载所有数据unmountChildren-> unmouted->卸载节点

  

测试代码如下:

<template>
  <life-cycle v-if="lifeFlag"></life-cycle>
  <button @click="lifeFlag = !lifeFlag">创建与销毁</button>
</template>
<script setup lang="ts">
import lifeCycle from './components/lifeCycle.vue';
import { ref } from 'vue'
const lifeFlag = ref<Boolean>(true)
</script>

生命周期组件:

<template>
  <h3>我是组件</h3>
  <div ref="div">{{  str }}</div>
  <button @click="change">修改</button>
</template>

<script setup lang='ts'>
import { onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, 
onUnmounted, onUpdated, ref, onRenderTracked, onRenderTriggered } from 'vue';

// beforeCreate created setup语法糖是没有这两个函数的生命周期的
console.log('setup')
const str = ref<string>('组件')
const div = ref<HTMLDivElement>()
const change = () => {
  console.log('修改组件了')
  str.value = '修改组件了'
}
// 创建完成之前读不到dom
onBeforeMount(() => {
  console.log('创建完成之前-onBeforeMount', div.value)
})
// 创建完成
onMounted(() => {
  console.log('创建完成-onMounted', div.value)
})
// 更新组件之前
onBeforeUpdate(() => {
  console.log('更新组件之前-onBeforeUpdate', div.value?.innerText)
})
// 更新
onUpdated(() => {
  console.log('更新完成-onUpdated', div.value?.innerText)
})
// 销毁之前
onBeforeUnmount(() => {
  console.log('销毁之前-onBeforeUnmount')
})
// 销毁完成
onUnmounted(() => {
  console.log('销毁完成-onUnmounted')
})

// 依赖收集,用来调试用
onRenderTracked(e => {
  console.log('------onRenderTracked--', e)
})
// 触发依赖,用来调试用
onRenderTriggered(e => {
  console.log('------onRenderTriggered--', e)
})
</script>

 

 

 

 

  

 引用文章: https://xiaoman.blog.csdn.net/article/details/122811060

posted @ 2023-07-17 17:18  TheYouth  阅读(87)  评论(0编辑  收藏  举报