Vue 从 Vue 2 到 Vue 3:生命周期全图鉴与实战指南

avatar
莫雨IP属地:上海
02026-01-31:12:23:01字数 5683阅读 0

一张图理清变迁,三案例掌握迁移,告别“钩子迷航”


🌱 引言:为什么生命周期是 Vue 开发的“导航仪”?

生命周期钩子是 Vue 组件从诞生到消亡的“心跳节拍”。掌握它,你才能:
✅ 精准发起 API 请求
✅ 安全操作 DOM 元素
✅ 避免内存泄漏陷阱
✅ 高效组织复杂逻辑

而 Vue 3 带来的 Composition API 与术语革新,让许多开发者陷入“钩子迷航”。本文以对比图谱+迁移指南+实战案例,带你彻底打通任督二脉!


📊 一、生命周期全景对比图(建议收藏!)

flowchart TD
    A[Vue 实例创建] --> B{API 风格}
    
    B -->|选项式 Options API| C1[Vue 2]
    B -->|选项式 Options API| C2[Vue 3]
    B -->|组合式 Composition API| D[Vue 3]
    
    C1 --> E1[beforeCreate<br/>created<br/>beforeMount<br/>mounted<br/>beforeUpdate<br/>updated<br/>beforeDestroy⚠️<br/>destroyed⚠️]
    C2 --> E2[beforeCreate<br/>created<br/>beforeMount<br/>mounted<br/>beforeUpdate<br/>updated<br/>beforeUnmount✅<br/>unmounted✅]
    D --> E3[setup() 替代<br/>beforeCreate/created<br/>onBeforeMount()<br/>onMounted()<br/>onBeforeUpdate()<br/>onUpdated()<br/>onBeforeUnmount()<br/>onUnmounted()]
    
    E1 -.->|迁移重点| F[⚠️ beforeDestroy/destroyed<br/>→ beforeUnmount/unmounted]
    E2 --> G[术语统一:<br/>“卸载”替代“销毁”]
    E3 --> H[逻辑聚合:<br/>相关代码集中管理]

🔑 核心变迁速览表

钩子阶段Vue 2 (Options)Vue 3 (Options)Vue 3 (Composition)关键变化
创建阶段beforeCreate``created保留(兼容)setup() 内逻辑二者被 setup 合并替代
挂载阶段beforeMount``mounted保留onBeforeMount``onMounted命名加 on 前缀
更新阶段beforeUpdate``updated保留onBeforeUpdate``onUpdated同上
销毁阶段beforeDestroy⚠️destroyed⚠️beforeUnmount**unmounted✅**onBeforeUnmount``onUnmounted术语革新:卸载 ≠ 销毁
新增能力-renderTracked``renderTriggeredonRenderTracked``onRenderTriggered调试响应式依赖

💡 为什么改名?
Vue 3 中组件是“卸载”(unmount)而非“销毁”(destroy)——实例仍可被缓存复用(如 <KeepAlive>),术语更精准!


🔄 二、迁移实战:三步平滑过渡

✅ 场景1:选项式 API 迁移(最小改动)

// Vue 2
export default {
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize)
  },
  destroyed() {
    console.log('组件销毁')
  }
}

// Vue 3 (Options API) —— 仅改名!
export default {
  beforeUnmount() { // ✅ 替换 beforeDestroy
    window.removeEventListener('resize', this.handleResize)
  },
  unmounted() {     // ✅ 替换 destroyed
    console.log('组件卸载')
  }
}

📌 提示:Vue 3 仍兼容 beforeDestroy/destroyed,但控制台会警告,强烈建议更新

✅ 场景2:Composition API 重构(逻辑聚合典范)

<!-- Vue 2 Options API(逻辑分散) -->
<script>
export default {
  data() { return { timer: null } },
  mounted() {
    this.timer = setInterval(() => this.fetchData(), 5000)
  },
  beforeDestroy() {
    clearInterval(this.timer)
  },
  methods: {
    fetchData() { /* ... */ }
  }
}
</script>

<!-- Vue 3 Composition API(逻辑内聚) -->
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { useFetch } from '@/composables' // 自定义组合函数

const { data, error, refresh } = useFetch('/api/status')
const timer = ref(null)

// 聚合:数据 + 定时器 + 清理
onMounted(() => {
  timer.value = setInterval(refresh, 5000)
  console.log('组件已挂载,开始轮询')
})

onUnmounted(() => {
  clearInterval(timer.value)
  console.log('组件卸载,清理定时器')
})
</script>

优势:相关逻辑(数据获取+定时器+清理)集中管理,可读性与可维护性飙升!


🛠️ 三、高频实战案例(附避坑指南)

💡 案例1:防内存泄漏——事件监听器清理

// Composition API 正确写法
import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  const handler = () => console.log('resize')
  window.addEventListener('resize', handler)
  
  // ✅ 关键:保存移除函数引用
  onUnmounted(() => {
    window.removeEventListener('resize', handler)
  })
})

错误写法:在 onUnmounted 中直接写新函数 → 无法移除监听器!

💡 案例2:自定义组合函数封装(复用利器)

// composables/useScroll.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useScroll() {
  const scrollTop = ref(0)
  
  const onScroll = () => {
    scrollTop.value = window.scrollY
  }
  
  onMounted(() => {
    window.addEventListener('scroll', onScroll, { passive: true })
  })
  
  onUnmounted(() => {
    window.removeEventListener('scroll', onScroll)
  })
  
  return { scrollTop }
}

// 组件中直接使用
<script setup>
import { useScroll } from '@/composables'
const { scrollTop } = useScroll()
</script>

价值:滚动逻辑封装成“能力模块”,任意组件复用,彻底告别重复代码!

💡 案例3:调试响应式依赖(Vue 3 独占)

import { onRenderTracked, onRenderTriggered } from 'vue'

// 跟踪哪些响应式属性触发了渲染
onRenderTracked((event) => {
  console.log('依赖追踪:', event)
  // { target: ..., key: 'count', type: 'get' }
})

// 跟踪哪个属性变化触发了重新渲染
onRenderTriggered((event) => {
  console.log('触发更新:', event)
})

🔍 适用场景:排查“为什么组件反复渲染?”的性能问题神器!


⚠️ 四、避坑指南:血泪经验总结

陷阱正确姿势原理
updated 中修改状态nextTick 或计算属性避免无限循环更新
setup 中访问 thisgetCurrentInstance()(慎用)setupthis 上下文
忘记清理副作用所有 onMounted 配对 onUnmounted防止内存泄漏(定时器/监听器)
onUpdated 中操作 DOMnextTick 包裹确保 DOM 已更新
混淆 onBeforeUpdate 时机用于“更新前”读取旧 DOM 状态如:记录滚动位置再更新

🌟 五、最佳实践:写出优雅的生命周期代码

  1. 逻辑聚合原则
    → 将“数据获取+清理”封装到自定义组合函数(如 useFetch
  2. 副作用显式声明
    → 所有外部操作(API/事件/DOM)必须配对清理逻辑
  3. 避免过度使用钩子
    → 优先用 watch/computed 替代 updated 中的逻辑
  4. 命名清晰化
    // ❌ 模糊
    onMounted(() => { init() })
    
    // ✅ 明确
    onMounted(initChatWidget)
    onUnmounted(cleanupChatWidget)
    

📌 结语:生命周期是“术”,架构思维是“道”

Vue 3 的生命周期变革,本质是 从“配置碎片”到“逻辑聚合”的范式升级

  • Options API:适合简单组件,迁移成本低
  • Composition API:复杂业务首选,逻辑复用能力碾压

🌱 记住这句话
“不要问‘该用哪个钩子’,而要问‘这段逻辑属于什么职责’。”
当你开始用 useXxx 封装能力,用 onUnmounted 守护资源——
你已真正拥抱 Vue 3 的工程化哲学。


📎 附录:速查备忘单(打印贴屏!)

场景Vue 2Vue 3 OptionsVue 3 Composition
初始化数据createdcreatedsetup() 内直接写
操作 DOMmountedmountedonMounted(() => { ... })
清理资源beforeDestroybeforeUnmountonBeforeUnmount(() => { ... })
监听更新updatedupdatedonUpdated(() => { ... })
调试渲染--onRenderTracked / onRenderTriggered

🔗 延伸学习

掌握生命周期,不是记住钩子名字,而是理解组件生命的每一次呼吸。
现在,打开你的编辑器,用 onMounted 写下今日第一行优雅代码吧! 💚

总资产 0
暂无其他文章

热门文章

暂无热门文章