Back

理解 Vue.js 中的生命周期钩子

理解 Vue.js 中的生命周期钩子

如果你正在构建 Vue 应用程序,并且想知道何时获取数据、清理资源或与 DOM 交互,你需要理解生命周期钩子。这些钩子是 Vue 3 中组件行为的核心,然而许多开发者在了解应该使用哪个钩子以及何时使用方面仍有困惑。

本文使用组合式 API 解释 Vue 3 的生命周期钩子,涵盖从组件创建到销毁的每个阶段,并提供可以立即应用的实用示例。

核心要点

  • setup 钩子取代了 Vue 2 选项式 API 中的 beforeCreate 和 created
  • onMounted 是在组件渲染后进行 DOM 操作和 API 调用的理想选择
  • 始终在 onUnmounted 中清理资源以防止内存泄漏
  • 生命周期钩子必须在 setup 函数内同步调用

Setup 钩子:组件的入口点

setup 钩子是 Vue 3 组合式 API 的基石,取代了 Vue 2 中的 beforeCreatecreated。它在组件实例完全初始化之前运行,使其成为定义响应式状态和组合组件逻辑的完美位置。

import { ref, reactive } from 'vue'

export default {
  setup(props, context) {
    const count = ref(0)
    const user = reactive({ name: '', email: '' })
    
    // Logic runs immediately, before template compilation
    console.log('Component initializing')
    
    return { count, user }
  }
}

与 Vue 2 的选项式 API 不同,setup 函数接收 propscontext 作为参数,让你可以直接访问组件属性而无需使用 this

挂载阶段:onBeforeMount 和 onMounted

onBeforeMount() - DOM 前的准备工作

onBeforeMount 钩子在 setup 之后但在组件的 DOM 创建之前触发。将其用于需要在渲染之前发生但不需要 DOM 访问的操作。

import { onBeforeMount } from 'vue'

export default {
  setup() {
    onBeforeMount(() => {
      // Initialize non-DOM dependent resources
      console.log('Template compiled, DOM not yet created')
    })
  }
}

onMounted() - DOM 就绪操作

onMounted 是大多数与 DOM 相关的初始化发生的地方。组件的模板已被渲染并插入到文档中,这使得访问元素和初始化第三方库变得安全。

import { ref, onMounted } from 'vue'

export default {
  setup() {
    const chartContainer = ref(null)
    
    onMounted(async () => {
      // Fetch data after component mounts
      const data = await fetch('/api/data').then(r => r.json())
      
      // Initialize chart library with DOM element
      // Assuming Chart is imported from a charting library
      new Chart(chartContainer.value, { data })
    })
    
    return { chartContainer }
  }
}

更新阶段:响应式状态变化

onBeforeUpdate() - 渲染前逻辑

当响应式数据变化触发重新渲染时,onBeforeUpdate 首先运行。这是你在 Vue 更新 DOM 之前读取当前 DOM 状态的最后机会。

import { onBeforeUpdate } from 'vue'

export default {
  setup() {
    onBeforeUpdate(() => {
      // Capture current scroll position before DOM updates
      const scrollY = window.scrollY
      // Store or use scrollY as needed
    })
  }
}

onUpdated() - 渲染后操作

在 Vue 更新 DOM 之后,onUpdated 触发。这里要小心——修改响应式状态可能会导致无限循环。

import { onUpdated } from 'vue'

export default {
  setup() {
    onUpdated(() => {
      // DOM has been updated
      // Use nextTick() for specific state change reactions
      console.log('Component re-rendered')
    })
  }
}

卸载阶段:组件清理

onBeforeUnmount() - 清理前任务

在组件被移除之前,onBeforeUnmount 让你最后一次访问完全功能的组件。

import { onBeforeUnmount, reactive } from 'vue'

export default {
  setup() {
    const state = reactive({ data: 'important info' })
    
    onBeforeUnmount(() => {
      // Save component state or notify external systems
      localStorage.setItem('lastState', JSON.stringify(state))
    })
    
    return { state }
  }
}

onUnmounted() - 资源清理

onUnmounted 对于防止内存泄漏至关重要。在这里清理事件监听器、定时器和订阅。

import { onMounted, onUnmounted } from 'vue'

export default {
  setup() {
    let timer
    
    const handleResize = () => {
      console.log('Window resized')
    }
    
    onMounted(() => {
      timer = setInterval(() => {
        console.log('Polling...')
      }, 1000)
      
      window.addEventListener('resize', handleResize)
    })
    
    onUnmounted(() => {
      clearInterval(timer)
      window.removeEventListener('resize', handleResize)
    })
  }
}

实用模式和最佳实践

在使用 Vue 3 生命周期方法时,请记住以下关键点:

  1. 始终从 ‘vue’ 导入钩子后再使用它们
  2. 在 setup() 内同步调用钩子——不要在回调或 Promise 中调用
  3. Vue 2 到 Vue 3 的迁移:beforeDestroy 现在是 onBeforeUnmount,destroyed 现在是 onUnmounted
  4. 服务端渲染:挂载和更新钩子在 SSR 期间不会运行

对于测试带有生命周期钩子的组件,使用 Vue Test Utils 来正确触发和断言钩子行为。

结论

Vue 3 的组合式 API 生命周期钩子在每个阶段为你的组件行为提供精确控制。通过理解每个钩子何时触发以及哪些资源可用,你可以编写更清晰、性能更好的组件。从 setup() 开始进行初始化,使用 onMounted() 进行 DOM 操作,并始终在 onUnmounted() 中清理以防止内存泄漏。

常见问题

可以,你可以在单个 setup 函数中多次调用同一个生命周期钩子。Vue 将按照它们注册的顺序执行它们。这对于按功能而不是生命周期阶段组织代码很有用。

onMounted 在组件首次渲染到 DOM 后运行一次。nextTick 等待下一个 DOM 更新周期,可以在代码的任何地方使用,而不仅仅是在生命周期钩子中。当你需要等待特定的响应式变化反映到 DOM 中时,使用 nextTick。

可以,生命周期钩子与 script setup 完美配合。只需导入并直接调用它们,无需包装在 setup 函数中。script setup 语法会自动为你处理 setup 上下文。

将生命周期钩子逻辑包装在 try-catch 块中进行错误处理。Vue 3 还提供了 onErrorCaptured 钩子来捕获来自子组件的错误。对于全局错误处理,在创建 Vue 应用程序时使用 app.config.errorHandler。

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay