2. 各阶段核心钩子 + 用途(Vue2/Vue3 对应)
| 阶段 | Vue2 钩子 | Vue3 组合式 API 钩子 | 核心用途 | 注意事项 |
|---|---|---|---|---|
| 创建阶段 | beforeCreate |
无(setup 替代) | 实例刚初始化,data/methods/props 均未挂载,无法访问 |
几乎不用,仅特殊初始化(如自定义事件总线) |
created |
setup 内部(最早) |
实例初始化完成,data/methods/props 已挂载,可访问数据但 DOM 未生成 |
1. 发起初始化数据请求(无需等待 DOM);2. 初始化非 DOM 相关逻辑(如定时器) | |
| 挂载阶段 | beforeMount |
onBeforeMount |
模板编译完成,即将挂载到真实 DOM,$el 未生成 |
可修改数据(不会触发额外更新),不推荐操作 DOM |
mounted |
onMounted |
组件挂载到真实 DOM 完成,$el 可用 |
1. 操作真实 DOM(如初始化第三方库:ECharts、富文本);2. 绑定事件监听 | |
| 更新阶段 | beforeUpdate |
onBeforeUpdate |
数据更新,虚拟 DOM 重新渲染前 | 读取当前 DOM 状态(如获取元素尺寸),不可修改数据(会触发无限更新) |
updated |
onUpdated |
数据更新,真实 DOM 重新渲染完成 | 操作更新后的 DOM(如滚动到指定位置),避免修改数据(易触发无限更新) | |
| 销毁阶段 | beforeUnmount |
onBeforeUnmount |
组件即将卸载,实例仍完整可用 | 核心:清理资源(取消定时器、解绑事件、取消请求、销毁第三方库实例) |
unmounted |
onUnmounted |
组件已卸载,实例销毁 | 极少用,仅确认资源清理完成(如日志上报) |
3. 实战示例(Vue3 组合式 API)
vue
xml
<script setup>
import { ref, onMounted, onUpdated, onBeforeUnmount } from 'vue';
import axios from 'axios';
const count = ref(0);
let timer = null;
let chart = null;
// 对应 created:初始化数据请求
const fetchData = async () => {
const res = await axios.get('/api/data');
console.log('初始化数据:', res.data);
};
fetchData();
// 对应 mounted:操作 DOM + 初始化第三方库
onMounted(() => {
console.log('DOM 挂载完成');
// 初始化 ECharts
chart = echarts.init(document.getElementById('chart'));
chart.setOption({ /* 配置 */ });
// 绑定窗口事件
window.addEventListener('resize', handleResize);
// 启动定时器
timer = setInterval(() => count.value++, 1000);
});
// 对应 updated:操作更新后的 DOM
onUpdated(() => {
console.log('DOM 更新完成,当前count:', count.value);
});
// 对应 beforeUnmount:清理资源(核心!)
onBeforeUnmount(() => {
console.log('组件即将卸载,清理资源');
clearInterval(timer); // 清除定时器
window.removeEventListener('resize', handleResize); // 解绑事件
chart?.dispose(); // 销毁 ECharts 实例
axios.CancelToken.source().cancel('请求取消'); // 取消未完成的请求
});
const handleResize = () => chart?.resize();
</script>
三、React 生命周期(类组件 + 函数组件)
React 类组件有明确的生命周期钩子,函数组件无原生生命周期,需通过 useEffect 模拟,核心阶段可对应到 Vue 的 "创建 - 挂载 - 更新 - 销毁"。
1. React 类组件生命周期(核心 6 个钩子)
| 阶段 | 类组件钩子 | 对应 Vue 阶段 | 核心用途 |
|---|---|---|---|
| 挂载阶段 | constructor |
beforeCreate/created | 初始化 state、绑定函数 this(如 this.handleClick = this.handleClick.bind(this)) |
componentDidMount |
mounted | 1. 发起初始化数据请求;2. 操作 DOM;3. 绑定事件 / 初始化第三方库 | |
| 更新阶段 | shouldComponentUpdate |
无(Vue 自动优化) | 返回布尔值,控制是否触发重渲染(性能优化,可替代 React.memo) |
componentDidUpdate |
updated | 数据更新后操作 DOM(如依赖 props 变化重新请求数据) | |
| 销毁阶段 | componentWillUnmount |
beforeUnmount | 清理资源(取消定时器、解绑事件、取消请求) |
| 错误捕获 | componentDidCatch |
无(Vue 用 errorCaptured) | 捕获子组件抛出的错误,避免应用崩溃 |
2. React 函数组件(useEffect 模拟生命周期)
函数组件通过 useEffect 的依赖数组控制执行时机,对应类组件生命周期:
| useEffect 写法 | 对应类组件钩子 | 核心用途 |
|---|---|---|
useEffect(() => {}, []) |
componentDidMount |
组件挂载后执行(仅 1 次):请求数据、绑定事件、初始化第三方库 |
useEffect(() => {}, [dep]) |
componentDidUpdate |
依赖项变化时执行:如 ID 变化重新请求数据 |
useEffect(() => { return () => {} }, []) |
componentWillUnmount |
组件卸载前执行:清理资源(清除定时器、解绑事件) |
useEffect(() => {}) |
无(mount + update) | 每次渲染后执行(不推荐,易引发性能问题) |
3. 实战示例(React 函数组件)
jsx
javascript
import { useState, useEffect } from 'react';
import axios from 'axios';
function UserList({ userId }) {
const [list, setList] = useState([]);
let timer = null;
// 1. 对应 componentDidMount:挂载后请求数据 + 初始化
useEffect(() => {
// 发起请求
const fetchData = async () => {
const res = await axios.get(`/api/user/${userId}`);
setList(res.data);
};
fetchData();
// 绑定事件
window.addEventListener('resize', handleResize);
// 启动定时器
timer = setInterval(() => console.log('定时器运行'), 1000);
// 2. 对应 componentWillUnmount:卸载前清理资源
return () => {
clearInterval(timer);
window.removeEventListener('resize', handleResize);
axios.CancelToken.source().cancel('请求取消');
};
}, [userId]); // 3. 对应 componentDidUpdate:userId 变化重新执行
// 4. 对应 componentDidUpdate:更新后操作 DOM
useEffect(() => {
if (list.length > 0) {
console.log('列表更新完成,滚动到顶部');
document.getElementById('list').scrollTop = 0;
}
}, [list]);
const handleResize = () => console.log('窗口变化');
return (
<div id="list">
{list.map(item => <div key={item.id}>{item.name}</div>)}
</div>
);
}
四、各阶段核心使用原则(通用)
1. 创建 / 挂载阶段(初始化)
- 禁止操作 DOM :
created(Vue)/constructor(React)阶段 DOM 未生成,操作 DOM 会报错; - 数据请求优先 :初始化数据请求可在
created(Vue)/componentDidMount(React)中发起,无需等待 DOM; - 第三方库初始化 :必须在 DOM 挂载完成后(
mounted/componentDidMount)执行(如 ECharts 需要 DOM 节点)。
2. 更新阶段(数据变化)
- 避免无限循环 :在
updated/componentDidUpdate中修改数据时,必须加条件判断(如对比新旧值); - 性能优化 :React 用
shouldComponentUpdate/React.memo,Vue 用computed/watch减少不必要的更新。
3. 销毁阶段(资源清理)
- 核心必做:所有手动绑定的资源(定时器、事件监听、第三方库实例、未完成的请求)必须在此阶段清理,否则会导致内存泄漏;
- 禁止修改状态:销毁阶段修改状态无意义(组件即将卸载,不会触发更新)。
五、Vue vs React 生命周期核心对应
| Vue 钩子 | React 类组件钩子 | React 函数组件写法 | 核心场景 |
|---|---|---|---|
| created | constructor + componentDidMount | useEffect (() => {}, []) 内部 | 初始化数据请求 |
| mounted | componentDidMount | useEffect(() => {}, []) | 操作 DOM、初始化第三方库 |
| updated | componentDidUpdate | useEffect(() => {}, [dep]) | 数据更新后操作 DOM |
| beforeUnmount | componentWillUnmount | useEffect(() => { return () => {} }, []) | 清理资源 |
总结
- 核心阶段:所有框架的生命周期都可归纳为「创建→挂载→更新→销毁」4 大阶段,用途高度一致;
- 核心原则:初始化逻辑(数据请求)放创建 / 挂载阶段,DOM 操作放挂载 / 更新阶段,资源清理放销毁阶段;
- 写法差异 :Vue 有明确的生命周期钩子,React 类组件同理,函数组件需用
useEffect模拟; - 避坑重点:销毁阶段必须清理资源(防内存泄漏),更新阶段修改数据需加条件(防无限循环)。
简单记:生命周期的核心是 "在正确的时间做正确的事"------ 初始化找 "挂载",更新找 "更新",清理找 "销毁"。