Skip to content
文章目录

组件各种情况的重新渲染和钩子函数触发时机

onMounted, onUpdated, router-view, keep-alive

vue
<!--

@file: Home.vue
@author: pan
-->
<script lang="ts">
export default {
  name: 'Home',
}
</script>
<script setup lang="ts">
import { onMounted, onUpdated, ref } from 'vue'

let mountedDate = ref<string>()
let updatedDate = ref<string>()
onMounted(() => {
  console.log('onMounted Home')
  /**
   * 修改 mountedDate 会触发一次 界面重新渲染,然后触发 onUpdated 钩子。因为 template 代码块中使用了该 响应式变量
   */
  mountedDate.value = new Date().toLocaleTimeString()
})
onUpdated(() => {
  /*
   * 因为 onMounted 之后执行了 mountedDate.value = new Date().toLocaleTimeString() ,
   * 更新了一个render函数(template代码块可以看作是render函数)中使用到的响应式变量所以会触发界面重新渲染,
   * 因此会在 onMounted 之后,立刻触发 onUpdated
   */
  /**
   * 使用了 keep-alive 之后,只要路由切换回当前组件,就会触发 onUpdated 钩子。
   * 这里就引发一个思考:什么时候会触发 onUpdated 钩子?
   * 答:vue引发的界面重新渲染一定触发 onUpdated 钩子
   * 暂时发现,以下两种形式的界面重新渲染会触发 onUpdated 钩子:
   * 1. render 函数(即:template 代码块)中使用到的响应式变量发生了变更,会触发界面重新渲染
   * 2. 使用了 router-view 然后被 keep-alive 缓存的组件,路由切换时,组件从冻结状态变为激活状态,会触发界面重新渲染(即使当前界面和上一次界面一摸一样,那算界面重新渲染。暂时没有办法解释这种行为,因为如果只是使用 keep-alive 缓存组件,而不使用 router-view,此时组件从冻结状态变成激活状态是不会触发 onUpdated 钩子的)
   */
  console.log('onUpdated Home')
  /**
   * onUpdated 中又修改了一个 render 函数中的响应式变量,所以会引起界面更新,所以会在界面更新之后又触发一次 onUpdated,
   * 之所以不会一直这样触发下去,是因为两次界面重绘间隔事件很短,使得 updatedDate 第一次的值和第二次的值是一样的,所以才没有形成 onUpdated 无限循环。
   * 只要延迟更新 updatedDate 就会形成 onUpdated 无限循环
   */
  updatedDate.value = new Date().toLocaleTimeString()
})
</script>

<template>
  <div>mountedDate: {{ mountedDate }}</div>
  <!-- <div>updatedDate: {{ updatedDate }}</div> -->
  <!-- <div>renderDate: {{ new Date().toLocaleTimeString() }}</div> -->
  <ul>
    <li><router-link to="/test-01">Go test 01</router-link></li>
    <li><router-link to="/test-02">Go test 02</router-link></li>
  </ul>
  <hr />
  <router-view v-slot="{ Component }">
    <keep-alive>
      <component :is="Component"></component>
    </keep-alive>
  </router-view>
</template>

<style lang="scss" scoped></style>