Vue 2 / Vue 3 生命周期
生命周期这题,面试官通常不是想听你背钩子名,而是想确认你是否真的理解:
- 组件在什么阶段初始化数据、建立响应式、生成 DOM、更新 DOM、销毁副作用
- Vue 2 和 Vue 3 在“写法”和“时机表达”上到底差在哪
- 哪些业务应该放在哪个阶段做,为什么
本文默认对比 Vue 2.x Options API 和 Vue 3.x Composition API / Options API。
面试速答(30 秒版 TL;DR)
- 生命周期本质上就是组件从 创建 -> 挂载 -> 更新 -> 卸载 -> 缓存激活/失活 的一套时机点。
- Vue 2 常背的一条线是:
beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed。 - Vue 3 仍然有 Options API 生命周期,但在实际项目里更常用的是组合式 API:
setup、onMounted、onUpdated、onUnmounted等。 - Vue 3 里最重要的变化不是“钩子改名”本身,而是:
- 组合式 API 让同一阶段的逻辑可以按功能聚合
- 卸载钩子从
beforeDestroy/destroyed改成beforeUnmount/unmounted setup()成了创建阶段的主要入口,很多初始化逻辑不再写进created
keep-alive是加分点:它不是销毁重建,而是activated/deactivated。
一、先建立心智模型:生命周期解决的是什么问题
组件不是“函数一跑就完了”,它有一个完整的存在周期:
- 框架先创建组件实例
- 初始化
props、data、computed、watch、响应式依赖 - 执行渲染函数,得到 VNode
- 把 VNode patch 成真实 DOM
- 数据变化后重新渲染、比对、更新 DOM
- 组件离开页面时销毁实例、事件、定时器、订阅
所以生命周期的本质,是给业务代码提供“插入点”。
二、Vue 2 生命周期主线
1. 创建阶段
beforeCreate:实例刚创建,data、props、methods还没完成代理。created:响应式、方法、监听等已初始化完成,但还没有真实 DOM。
这个阶段适合做:
- 初始化普通数据
- 发起不依赖 DOM 的请求
- 注册事件总线、订阅等
这个阶段不适合做:
- 操作真实 DOM
- 读取组件渲染后的尺寸位置
2. 挂载阶段
beforeMount:首次渲染前mounted:组件已经挂到页面,真实 DOM 可用
适合放在 mounted 的逻辑:
- DOM 测量
- 第三方 DOM 库初始化
- 依赖
ref的操作
3. 更新阶段
beforeUpdate:响应式数据变了,但 DOM 还没更新updated:DOM 已完成本轮更新
面试里要强调:
- Vue 的更新不是同步立即改 DOM,而是调度后批量刷新
- 如果你要拿“更新后的 DOM”,一般看
updated或nextTick
4. 卸载阶段
beforeDestroydestroyed
这个阶段要清理:
setTimeout/setInterval- 手动绑定的 DOM 事件
- WebSocket、订阅、观察器
5. 缓存组件阶段
被 keep-alive 包住的组件,不会频繁销毁重建,而是:
- 首次进入:照常创建、挂载
- 切走时:触发
deactivated - 切回时:触发
activated
这也是为什么标签页缓存、列表返回保留滚动位置,经常配合 keep-alive。
三、Vue 3 生命周期怎么理解
1. Options API 仍然存在,但命名更统一
Vue 3 不是把生命周期推翻重来,而是做了统一:
| Vue 2 | Vue 3 |
|---|---|
beforeDestroy | beforeUnmount |
destroyed | unmounted |
activated | activated |
deactivated | deactivated |
其余创建、挂载、更新阶段的含义基本一致。
2. 组合式 API 下,setup() 是创建阶段入口
Vue 3 真正的变化点,是大量逻辑不再分散在 data、methods、watch、created 里,而是放进 setup()。
可以把它理解成:
- 组件初始化早期执行
setup() - 在这里声明响应式状态、计算属性、监听、副作用
- 再配合
onMounted、onUpdated、onUnmounted等注册各阶段逻辑
最重要的答题点:
setup()里没有组件实例thissetup()更像“组件逻辑装配阶段”- 原来放在
beforeCreate/created的很多逻辑,在 Vue 3 里会自然转移到setup()
3. Vue 3 常用生命周期 API
import { onMounted, onUpdated, onUnmounted, onActivated, onDeactivated } from 'vue'
最常考的对应关系:
| 场景 | Vue 2 | Vue 3 常用写法 |
|---|---|---|
| 挂载后操作 DOM | mounted | onMounted |
| 更新后拿新 DOM | updated | onUpdated 或 nextTick |
| 卸载前清理副作用 | beforeDestroy/destroyed | onUnmounted |
| keep-alive 激活/失活 | activated/deactivated | onActivated/onDeactivated |
四、Vue 2 和 Vue 3 的关键差异,不要只答“名字变了”
1. 差异一:逻辑组织方式变了
Vue 2 的问题是:同一块业务逻辑会分散在多个选项里。
例如一个“用户列表”功能,可能拆在:
datacomputedwatchmountedmethods
Vue 3 则可以按“功能”聚合:
import { ref, onMounted, watch } from 'vue'
export function useUserList() {
const list = ref([])
const keyword = ref('')
onMounted(loadUsers)
watch(keyword, loadUsers)
async function loadUsers() {
// ...
}
return { list, keyword, loadUsers }
}
这就是 Vue 3 生命周期变化背后的真正收益:时机仍然存在,但逻辑组织方式更合理。
2. 差异二:销毁语义更准确
Vue 2 的 destroy 容易让人误以为是“彻底物理销毁 DOM”。
Vue 3 改成 unmount,更贴近渲染器语义:组件从当前渲染树卸载。
3. 差异三:组合式 API 的注册必须同步完成
这是高频追问。
像 onMounted、onUnmounted 这类组合式生命周期注册,通常都要求在 setup() 的同步阶段完成。不要在异步回调里再临时注册,否则时机可能丢失。
五、典型业务到底该放哪
1. 请求数据放哪
面试里更稳的答法是:
- 不依赖 DOM 的初始化请求:
- Vue 2 可放
created - Vue 3 常放
setup()中触发,或onMounted
- Vue 2 可放
- 如果请求结果会影响首屏渲染,但不需要 DOM,优先尽早发起
- 如果请求依赖 DOM 容器尺寸、第三方实例,就放
mounted/onMounted
2. DOM 操作放哪
- Vue 2:
mounted、updated - Vue 3:
onMounted、onUpdated、nextTick
3. 清理逻辑放哪
- Vue 2:
beforeDestroy/destroyed - Vue 3:
onUnmounted
一个最小例子:
import { onMounted, onUnmounted } from 'vue'
let timer: ReturnType<typeof setInterval> | null = null
onMounted(() => {
timer = setInterval(() => {
console.log('polling')
}, 1000)
})
onUnmounted(() => {
if (timer) clearInterval(timer)
})
六、生命周期执行顺序怎么背
Vue 2 常规组件
beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed
Vue 3 组合式 API 口径
可以记成:
setup -> onBeforeMount -> onMounted -> onBeforeUpdate -> onUpdated -> onBeforeUnmount -> onUnmounted
如果用了缓存组件,再补上:
onActivated / onDeactivated
七、典型题 & 标准答法
Q1:created 和 mounted 区别是什么?
答:created 时组件实例和响应式数据已经就绪,但真实 DOM 还没挂载;mounted 时 DOM 已经生成,可以拿 ref、做尺寸计算、初始化图表或第三方库。是否依赖 DOM,是二者最核心的分界线。
Q2:Vue 3 里还有没有 created?
答:有,Vue 3 的 Options API 仍支持这些钩子。但在实际 Vue 3 项目里,更常把初始化逻辑放进 setup(),再配合 onMounted 等组合式生命周期,因此面试更常考的是 setup 这一套。
Q3:为什么 keep-alive 不走销毁重建?
答:因为它的目标就是缓存组件实例和状态,避免频繁重新创建。切走时不是 unmount,而是失活 deactivated;切回时是激活 activated。
八、常见误区
- 误区 1:把生命周期理解成“固定背诵题”。 真正重要的是“这个阶段能不能拿到 DOM、能不能拿到实例、适不适合清理副作用”。
- 误区 2:所有请求都必须放
mounted。 不依赖 DOM 的请求没必要等到挂载后再发。 - 误区 3:
updated里无脑继续改响应式数据。 这容易造成重复更新,甚至死循环。 - 误区 4:忘记清理副作用。 生命周期不只是“开始做事”,更重要的是“结束时收口”。
速记要点
- 生命周期本质:组件各阶段的业务插入点
- Vue 2 主线:创建、挂载、更新、销毁、缓存激活
- Vue 3 重点:
setup()+onXxx - DOM 操作看
mounted/onMounted - 清理副作用看
beforeDestroy/destroyed或onUnmounted keep-alive记住activated/deactivated