Vue3-16 生命周期

当涉及到 Vue.js 的生命周期时,Vue 3 提供了一些新的概念和方式来管理组件的生命周期。在本文中,我们将深入探讨 Vue 3 的生命周期,并介绍每个生命周期钩子的作用和使用场景。

Vue 3 的生命周期概述

在 Vue 3 中,组件的生命周期主要分为三个阶段:

  1. 创建阶段(Initialization)
  2. 更新阶段(Mounting and Updating)
  3. 销毁阶段(Unmounting)

每个阶段都有相应的生命周期钩子函数,可以让开发者在不同的阶段执行特定的逻辑。

下面的例子中左边为选项式Api右边是组合式Api

创建阶段(Initialization)

在创建阶段,组件的实例和其相关的数据正在被初始化。这个阶段包括以下几个生命周期钩子:

beforeCreate
  • 触发时机: 在实例初始化之后,数据观测 (data 和 props 的初始化) 之前被调用。
  • 使用场景: 适合在组件实例被创建之前执行一些初始化工作,但此时组件实例还未完全被创建,因此无法访问到 datapropsmethods 和 computed 等成员。通常在此阶段处理一些全局配置或初始化非响应式的数据。
<script>
export default {
  beforeCreate() {
    console.log('beforeCreate hook triggered');
    console.log('Data is not reactive yet:', this.dataValue); // undefined
    this.nonReactiveData = 'Initial non-reactive data';
  },
  data() {
    return {
      dataValue: 'Hello, Vue!'
    };
  }
};
</script>

beforeCreate 钩子中,我们可以看到 dataValue 是不可访问的,因为此时 data 还未被初始化。但我们可以初始化非响应式的数据 this.nonReactiveData

created
  • 触发时机: 在实例创建完成后被调用,此时组件实例已完成数据观测 (data 和 props 的初始化),但是 DOM 元素还未生成,因此无法访问到 $el
  • 使用场景: 适合执行一些初始化操作,如异步请求数据、对数据的进一步处理,或者在组件创建完成后进行一些操作,如设置定时器、监听事件等。
<script>
export default {
  data() {
    return {
      message: ''
    };
  },
  created() {
    console.log('created hook triggered');
    console.log('Data is reactive now:', this.message); // 'Hello, Vue!'
    this.fetchData();
  },
  methods: {
    async fetchData() {
      try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        this.message = data.message;
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    }
  }
};
</script>

created 钩子中,我们可以访问和操作 data 中的数据,因为此时 Vue 已完成数据观测,数据是响应式的。在示例中,我们通过 fetchData 方法异步获取数据,并将其赋值给 message

组合式Api中不存在created和beforeCreate  基本上就是用setup代替

更新阶段(Mounting and Updating)

更新阶段是组件实例被创建之后,数据发生变化导致重新渲染时的阶段。这里涵盖了更多的生命周期钩子(括号里面为组合式Api对应的方法):

  • beforeMount(onBeforeMount):在挂载开始之前被调用:相关的 render 函数首次被调用。
  • mounted(onMounted):el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子函数。
  • beforeUpdate(onBeforeUpdate):数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
  • updated(onUpdated):由于数据更改导致的虚拟 DOM 重新渲染和打补丁后调用。
<template>
  <div>
    <p>{{ message }}</p>
    <button @click="updateMessage">Update Message</button>
  </div>
</template>

<script>
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated } from 'vue';

export default {
  setup() {
    const message = ref('Hello, Vue!');

    // 在组合式 API 中使用生命周期钩子
    onBeforeMount(() => {
      console.log('Component is about to be mounted');
    });

    onMounted(() => {
      console.log('Component is mounted');
    });

    onBeforeUpdate(() => {
      console.log('Component is about to update');
    });

    onUpdated(() => {
      console.log('Component is updated');
    });

    const updateMessage = () => {
      message.value = 'Updated message!';
    };

    return {
      message,
      updateMessage
    };
  },
};
</script>

上面代码中,页面加载之后onBeforeMount和onMount顺序执行,点击按钮onBeforeUpdate获取到的还是变更之前的数据,onUpdate获取到的是变更之后的数据。

销毁阶段(Unmounting)

在组件实例被销毁时,销毁阶段的生命周期钩子函数将会被调用:

  • beforeUnmount(onBeforeUnmount:在卸载之前调用。在这一步,实例仍然完全可用。
  • unmounted(onUnmounted:在卸载完成后调用。该钩子函数用来清理一些组件内的事件监听器或定时器等资源。

当我们离开一个vue界面到达另一个vue界面时,有些未关闭的东西例如定时器是不会关闭的,这将消耗我们的系统资源,我们可以使用这两个方法来关闭定时器

const startTimer = () => {
  timerId.value = setInterval(() => {
    console.log('定时器执行中')
  }, 1000)
}

//如果不加,定时器一旦开始,返回其他页面时定时器根本不会被销毁,而是一直在执行
onUnmounted(() => {
  console.log('组件将被卸载')
  if (timerId.value) {
    clearInterval(timerId.value)
  }
})
onBeforeUnmount(() => {
  console.log('组件即将被卸载')
  // 在组件卸载前执行的逻辑,例如清除定时器、取消订阅等
  if (timerId.value) {
    clearInterval(timerId.value)
  }
})

在 Vue 3 的组合式 API 中,除了常见的生命周期钩子(如 onBeforeMountonMountedonBeforeUpdateonUpdated)外,还引入了一些新的生命周期钩子和钩子函数,用于更细粒度地控制和监控组件的行为。下面是这些生命周期钩子的详细介绍及使用方式:

errorCaptured(onErrorCaptured)

  • 作用:用于捕获组件及其子组件的任何错误。它常常用于捕获子组件报的错误,自己的错误好像捕获不了。
  • 参数
    • error:捕获到的错误对象。
    • instance:出现错误的组件实例。
    • info:关于错误的额外信息。
  • 返回值:钩子可以通过返回 false 来阻止错误继续向上传递。

使用示例

<LifeCycleError/>

// 使用 onErrorCaptured 捕获错误 自己的错误捕捉不到,只能捕捉子组件的内容
onErrorCaptured((error, component, info) => {
  // 记录错误信息
  errorRef.value = `Error: ${error.message}`;

  // 可以选择处理错误,或者在控制台打印错误信息
  console.error('Error captured in component:', component);
  console.error('Error info:', info);

  // 返回 false 表示阻止错误继续传播
  return true;
});

子组件中:

function fetchData(){
  let json = JSON.parse("{sa:as}")
}

这个方法会出现JSON转化异常,就可以被父页面中捕获。

activated(onActivated) 和 deactivated(onDeactivated)

onActivatedonDeactivated 用于监听组件的激活和失活状态变化。

使用示例

        <div v-if="flag">
          <keep-alive>
          <LifeCycleError/>
          </keep-alive>
        </div>
        <div v-else>      
          <keep-alive>
          <WelcomeItem/>
        </keep-alive>

子组件中:

onActivated(() => {
  console.log('Component is activated');
});
onDeactivated(() => {
   console.log('Component is deactivated');
});

当flag属性=true后。子组件中的onActivated会被激活,当为false之后,onDeactivated属性会被激活。

renderTriggered(onRenderTriggered)(Only dev)

  • 功能: 当响应式数据引起重新渲染时触发的钩子函数。
  • 使用场景: 主要用于调试和性能分析,可以在数据变化时触发自定义逻辑或记录日志,以便更好地理解何时和为什么会触发重新渲染。

示例:

import { onRenderTriggered } from '@vue/reactivity';

onRenderTriggered((event) => {
  console.log('Render triggered!', event);
  // 可以在这里执行自定义的逻辑
});

在上面的例子中,我们使用 onRenderTriggered 函数注册了一个回调函数,当响应式数据引起重新渲染时,会触发这个回调函数,并且会传入一个事件对象 event,可以用于进一步分析和调试。

renderTracked(onRenderTracked)(Only dev)

  • 功能: 当响应式数据被追踪到(即被访问)时触发的钩子函数。
  • 使用场景: 同样用于调试和性能分析,可以在数据被访问时触发自定义逻辑或记录日志,帮助理解数据的访问情况和优化性能。

示例:

import { onRenderTracked } from '@vue/reactivity';

onRenderTracked((event) => {
  console.log('Render tracked!', event);
  // 可以在这里执行自定义的逻辑
});

在这个示例中,我们使用 onRenderTracked 函数注册了一个回调函数,当响应式数据被追踪到时,会触发这个回调函数,并且同样会传入一个事件对象 event,用于进一步分析和调试。

serverPrefetch (onServerPrefetch)

在组件的 setup 函数中,通过 onServerPrefetch 钩子定义在服务端预取数据时执行的逻辑。

import { onServerPrefetch, ref } from 'vue';

export default {
  setup() {
    const data = ref(null);

    // 在服务端预取数据时执行的逻辑
    onServerPrefetch(async () => {
      // 模拟异步获取数据
      const result = await fetchData();
      data.value = result;
    });

    // 返回组件内部需要的数据或状态
    return {
      data
    };
  }
};
  1. 服务端预取数据的执行环境

    • onServerPrefetch 只在服务端执行,不会在客户端执行。这意味着你可以在此钩子内执行一些服务端专有的操作,比如通过 API 请求数据或者直接操作数据库。
    • Vue 会在服务端渲染期间自动调用 onServerPrefetch 钩子,并等待其完成,然后将结果一并传递到客户端。
  2. 客户端的数据同步

    当客户端接管页面并开始交互时,Vue 将使用服务端预取的数据初始化组件状态,避免不必要的数据请求。

  3. 注意事项

    • 在 onServerPrefetch 中可以使用 async 函数来处理异步逻辑,确保在数据获取完成前不会返回组件实例。
    • 可以在 onServerPrefetch 中执行任何服务端可用的操作,但需注意不要包含依赖于客户端环境的逻辑。
    • onServerPrefetch 使用条件比较苛刻,后期在SSR章节中详细解释一下这玩意。

下面是我随意写了个小例子:

LifeCycleError.vue

<!--条件和列表渲染-->
<template>
      <button  @click="fetchData">handleFetchData</button>
      {{ zhangsan }}
</template>
<script lang="ts" setup>
import { computed, nextTick } from 'vue'
import { ref } from 'vue'
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { onMounted, 
  onUpdated,
  onUnmounted,
  onBeforeMount,
  onBeforeUpdate,
  onBeforeUnmount,
  onRenderTracked,
  onRenderTriggered,onServerPrefetch,
  onErrorCaptured , onActivated,
  onDeactivated} from 'vue'

function fetchData(){
  let json = JSON.parse("{sa:as}")
}
const zhangsan=ref("四")
onRenderTracked((event) => {
    zhangsan.value="wu"
  console.log(`Render tracked for "${event.target}"`);
});

onRenderTriggered((event) => {
    zhangsan.value="liu"

  console.log(`Render triggered for "${event.target}"`);
});
onActivated(() => {
  console.log('Component is activated');
});
onDeactivated(() => {
   console.log('Component is deactivated');
});


</script>

<style scoped>
</style>

LifeCycle.vue

<!--条件和列表渲染-->
<template>
    <div id="vue2">

    </div>
    <div id="vue3">
      <button id="count" @click="count++">{{ count }}</button>
      <button @click="fetchData2">handleFetchData2</button>
      <div v-for="user in userAgeltTen">
        {{ user.userName }}
      </div>
        <div v-if="flag">
          <keep-alive>
          <LifeCycleError/>
          </keep-alive>
        </div>
        <div v-else>      
          <keep-alive>
          <WelcomeItem/>
        </keep-alive>

        </div>
    </div>
    {{ data2 }}
</template>
<script lang="ts">
import LifeCycleError from '../../components/LifeCycleError.vue'
import WelcomeItem from '../../components/WelcomeItem.vue'

export default {
  data() {
    return {
    }
  },
  beforeCreate(){
    
  },
  methods: {
  }
}
</script>
<script lang="ts" setup>
import { computed, nextTick } from 'vue'
import { ref } from 'vue'
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { inject,createSSRApp } from 'vue';
import { onMounted, 
  onUpdated,
  onUnmounted,
  onBeforeMount,
  onBeforeUpdate,
  onBeforeUnmount,
  onErrorCaptured,
  onServerPrefetch

} from 'vue'
const flag = ref(true)
const el = ref("zhangsan")
onMounted(() => {
  console.log(`vue3-onMounted-`+el.value)
})
const count = ref(0)
onUpdated(() => {
  // 文本内容应该与当前的 `count.value` 一致
  //数据被更新时就会调用,但是这里写的时候不要用el-button,可能抓不到
  console.log("onUpdated-"+document.getElementById('count').textContent)
  startTimer()
})

onBeforeUpdate(() => {
  // 文本内容应该与当前的 `count.value` 一致,点击一下此时还是0
  console.log("onBeforeUpdate-"+document.getElementById('count').textContent)
  startTimer()
})

const timerId = ref()
const startTimer = () => {
  timerId.value = setInterval(() => {
    console.log('定时器执行中')
  }, 1000)
}
//如果不加,定时器一旦开始,返回其他页面时定时器根本不会被销毁,而是一直在执行
onUnmounted(() => {
  console.log('组件将被卸载')
  if (timerId.value) {
    clearInterval(timerId.value)
  }
})
onBeforeUnmount(() => {
  console.log('组件即将被卸载')
  // 在组件卸载前执行的逻辑,例如清除定时器、取消订阅等
  if (timerId.value) {
    clearInterval(timerId.value)
  }
})


const data = ref();
//如果不加,定时器一旦开始,返回其他页面时定时器根本不会被销毁,而是一直在执行,一般用来初始化数据,create差不多,但是时机不同
onBeforeMount(() => {
  data.value = [
    "zhangsan","lisi"
  ] 
  console.log(data.value);
})
function fetchData2(){
  userVue[1].userName = "wangwu"
  flag.value = !flag.value
  let json = JSON.parse("{sa:as}")
}
const errorRef = ref();

// 使用 onErrorCaptured 捕获错误 自己的错误捕捉不到,只能捕捉子组件的内容
onErrorCaptured((error, component, info) => {
  // 记录错误信息
  errorRef.value = `Error: ${error.message}`;

  // 可以选择处理错误,或者在控制台打印错误信息
  console.error('Error captured in component:', component);
  console.error('Error info:', info);

  // 返回 false 表示阻止错误继续传播
  return true;
});



//定义一个数组
let users = [
  {
    userName: 'zhangsan',
    age: 9,
    sex: 'man'
  },
  {
    userName: 'lisi',
    age: 12,
    sex: 'woman'
  }
]

let userVue = reactive(users)

const userAgeltTen = computed(() => {
     console.log("计算属性执行了")
  return userVue.filter(user=>user.age>10)
})
//仅在SSR环境执行
onServerPrefetch(async () => {
  console.log('Fetching data on server...');
});


</script>
<style scoped>
</style>

    关注公众号:资小库,问题快速答疑解惑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会写爬虫的程序员B

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值