Vue 与react 生命周期对比
目录
- 一、Vue 2 生命周期
- 二、Vue 3 生命周期
- 三、React 生命周期
- 四、React Hooks 生命周期替代方案
- 五、三者对比总结
- 六、关键差异分析
- 七、最佳场景
一、Vue 2 生命周期
vue2的生命周期分为 创建、挂载、更新、销毁 四个阶段,共8个钩子
beforeCreate → created → beforeMount → mounted →
beforeUpdate → updated → beforeDestroy → destroyed
核心钩子功能:
1、创建阶段:
- beforeCreate:实例初始化后,数据观测和 event/watcher 事件配置前调用。
- created:实例已经创建完成,数据观测、property 和 method 计算、watch/event 事件回调已完成。
2、 挂载阶段:
- beforeMount:挂载开始前调用,此时 $el 尚未生成。
- mounted:挂载完成后调用,此时 $el 已生成,可以访问 DOM。
3、更新阶段:
- beforeUpdate:数据更新前调用,发生在虚拟 DOM 打补丁之前。
- updated:数据更新后调用,发生在虚拟 DOM 重新渲染和打补丁之后。
4、销毁阶段:
- beforeDestroy:实例销毁前调用,此时实例仍然完全可用。
- destroyed:实例销毁后调用,所有事件监听器和子实例已被销毁。
二、Vue 3 生命周期
Vue 3 的生命周期在组合式 API(Composition API)中进行了调整,与 Vue 2 基本对应,但名称有所变化,新增了 setup 作为入口点:
setup → onBeforeMount → onMounted →
onBeforeUpdate → onUpdated → onBeforeUnmount → onUnmounted
与 Vue 2 的对应关系
Vue 2 钩子 | Vue 3 组合式 API 等效方法 |
---|---|
beforeCreate | setup() 中初始化前 |
created | setup() 中初始化后 |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
errorCaptured | onErrorCaptured |
- | onRenderTracked(调试用) |
- | onRenderTriggered(调试用) |
三、React 生命周期
React 的生命周期分为挂载、更新、卸载三个阶段,主要通过类组件(Class Component)的方法实现:
挂载阶段:constructor → static getDerivedStateFromProps → render → componentDidMount
更新阶段:static getDerivedStateFromProps → shouldComponentUpdate → render → getSnapshotBeforeUpdate → componentDidUpdate
卸载阶段:componentWillUnmount
错误处理:static getDerivedStateFromError → componentDidCatch
核心钩子功能
1、挂载阶段:
- constructor:初始化 state 和绑定事件处理函数。
- static getDerivedStateFromProps:在渲染前从 props 更新 品state(很少使用)。
- render:返回 JSX 元素。
- componentDidMount:组件挂载后调用,可用于 DOM 操作、API 请求等。
2、更新阶段:
- static getDerivedStateFromProps:同上。
- shouldComponentUpdate:控制组件是否需要重新渲染(性能优化)。
- render:重新渲染。
- getSnapshotBeforeUpdate:在 DOM 更新前获取当前 DOM 状态。
- componentDidUpdate:组件更新后调用,可用于对比前后 props/state。
3、卸载阶段:
- componentWillUnmount:组件卸载前调用,清理定时器、事件监听器等。
4、错误处理:
- static getDerivedStateFromError:捕获子组件错误,更新 state 显示错误 UI。
- componentDidCatch:记录错误信息。
四、React Hooks 生命周期替代方案
React Hooks(如 useEffect)提供了函数式组件的生命周期管理方式:
useEffect(() => {// 相当于 componentDidMount + componentDidUpdatereturn () => {// 相当于 componentWillUnmount};
}, [dependencies]); // 依赖项数组控制触发时机
Hooks 与类组件生命周期的对应关系
类组件方法 | React Hooks 等效实现 |
---|---|
componentDidMount | useEffect(() => { … }, []) |
componentDidUpdate | useEffect(() => { … }, [deps]) |
componentWillUnmount | useEffect(() => { return () => { … } }, []) |
shouldComponentUpdate | React.memo(函数组件) |
五、三者对比总结
阶段 | Vue 2 | Vue 3 组合式 API | React 类组件 | ReactHooks |
---|---|---|---|---|
初始化 | beforeCreate | setup() 内 | constructor | 函数组件本身 |
- | created | setup() 内 | - | - |
挂载前 | beforeMount | onBeforeMount | render 前 (输出jsx) | - |
挂载后 | mounted | onMounted | componentDidMount | useEffect(() => {}) |
更新前 | beforeUpdate | onBeforeUpdate | render 前 | - |
更新后 | updated | onUpdated | componentDidUpdate | useEffect(() => {}) |
卸载前 | beforeDestroy | onBeforeUnmount | componentWillUnmount | useEffect(() => { return () => {…} }) |
卸载后 | destroyed | onUnmounted | - | - |
错误处理 | errorCaptured | onErrorCaptured | componentDidCatch | - |
六、关键差异分析
1、设计理念:
- Vue:生命周期钩子设计更直观,明确区分各阶段,适合初学者。
- React:生命周期复杂,尤其类组件中存在多个类似功能的钩子(如 componentWillReceiveProps 被弃用),需要理解底层原理。
2、状态管理:
- Vue:响应式系统自动追踪依赖,生命周期与数据变化强绑定。
- React:需手动通过 setState 触发更新,依赖 shouldComponentUpdate 优化性能。
3、函数式编程:
- Vue 3:组合式 API 支持函数式组织代码,但仍保留选项式 API。
- React:Hooks 强制使用函数式组件,彻底抛弃类组件的复杂生命周期。
4、性能优化:
- Vue:通过 watch、computed 自动优化依赖更新。
- React:需手动使用 React.memo、useMemo、useCallback 优化。
七、最佳场景
场景 1:初始化时获取数据(如 API 请求)
- 核心需求:组件首次加载时从后端 / 接口获取数据,初始化页面内容。
框架 / 范式 | 推荐 API / 生命周期函数 | 原因与注意事项 |
---|---|---|
Vue2(选项式) | created 或 mounted | - created:实例创建后(data/methods 已初始化,DOM 未挂载),适合早期数据请求(比 mounted 更早发起,减少等待时间)。 mounted:DOM 挂载后,若请求依赖 DOM 信息(如元素尺寸),用此钩子;否则优先 created。 |
Vue3(组合式) | onMounted(配合 setup) | - setup 执行时机在 Vue2 的 created 和 beforeMount 之间,此时可直接处理数据,但 API 请求通常放在 onMounted 中(更符合 “挂载后执行” 的语义,与 Vue2 的 mounted 行为一致)。 注意:setup 中无需手动调用,导入 onMounted 后注册回调即可。 |
React(类组件) | componentDidMount | - 组件首次挂载到 DOM 后执行,此时可安全发起 API 请求(类组件中数据初始化的标准时机)。 避免在 constructor 中请求(可能导致不必要的重复执行)。 |
React(Hooks) | useEffect(() => { … }, []) | - 空依赖数组的 useEffect 等价于 componentDidMount,仅在组件挂载后执行一次,适合发起一次性请求。 注意:依赖数组必须为空,否则会因依赖变化重复执行。 |
场景 2:DOM 渲染完成后操作(如初始化第三方库)
框架 / 范式 | 推荐 API / 生命周期函数 | 原因与注意事项 |
---|---|---|
Vue2(选项式) | mounted | - 此时 DOM 已完全挂载,可通过 this.refs 获取 DOM 节点(如 this.$refs.chartDom),适合初始化依赖 DOM 的库。 若需在数据更新后重新初始化,需配合 updated。 |
Vue2(选项式) | onMounted | 与 Vue2 的 mounted 逻辑一致,通过 ref 获取 DOM 节点(如 const chartDom = ref(null),在 onMounted 中访问 chartDom.value)。 |
React(类组件) | componentDidMount | 组件挂载后 DOM 已存在,可通过 this.refs 或回调 ref 获取节点(如 this.chartDom),初始化第三方库。 |
React(Hooks) ) | useEffect(() => { … }, [domRef]) | 依赖 DOM 节点的 ref(如 const domRef = useRef(null)),确保 ref.current 已指向真实 DOM 后执行。- 注意:需将 ref 加入依赖数组,避免 DOM 未初始化时执行。 |
场景 3:监听数据 / Props 变化并响应
- 核心需求:当组件的 props、state 或数据变化时,执行特定逻辑(如重新计算、更新 DOM、发起请求)。
框架 / 范式 | 推荐 API / 生命周期函数 | 原因与注意事项 |
---|---|---|
Vue2(选项式) | watch 或 computed | - watch:监听具体数据(data/props)的变化,支持深度监听(deep: true)和立即执行(immediate: true),适合复杂逻辑(如数据变化后发起请求)。 computed:依赖数据变化自动计算衍生值,适合简单的 “数据→数据” 映射(如过滤列表)。 |
Vue3(组合式) | watch 或 watchEffect | - watch:需显式指定监听源(如 watch(() => props.id, (newVal) => { … })),支持深度监听和即时执行,与 Vue2 的 watch 类似。 watchEffect:自动追踪依赖(无需指定源),依赖变化时自动执行,适合 “副作用随依赖自动触发” 的场景(如数据变化后更新 DOM)。 |
React(类组件) | componentDidUpdate(prevProps, prevState) | 对比当前与之前的 props/state(如 if (this.props.id !== prevProps.id)),执行变化后的逻辑(如重新请求数据)。 必须加条件判断,否则会因每次更新触发无限循环。 |
React(Hooks) | useEffect(() => { … }, [deps]) | 依赖数组 deps 中的变量变化时执行回调,等价于 “监听 deps 变化”。 例:useEffect(() => { fetchData(id) }, [id]):当 id 变化时重新请求数据。 |
场景 4:组件卸载前清理副作用
- 核心需求:组件销毁 / 卸载时,清理定时器、事件监听、订阅等(避免内存泄漏)。
框架 / 范式 | 推荐 API / 生命周期函数 | 原因与注意事项 |
---|---|---|
Vue2(选项式) | beforeDestroy 或 destroyed | - beforeDestroy:组件即将销毁,此时仍可访问实例(data/methods),适合清理操作(如 clearInterval(timer)、移除事件监听 window.removeEventListener)。 destroyed:组件已销毁,实例属性可能已不可用,优先用 beforeDestroy |
Vue3(组合式) | onBeforeUnmount | 组件卸载前执行,与 Vue2 的 beforeDestroy 功能一致,在其中清理定时器、取消订阅(如 onBeforeUnmount(() => clearInterval(timer)))。 |
React(类组件) | componentWillUnmount | - 组件卸载前执行,清理定时器(clearInterval(this.timer))、移除事件监听(window.removeEventListener)、取消 API 请求(如 abortController.abort())。 |
React(Hooks) | useEffect(() => { return () => { … } }, []) | useEffect 的返回函数会在组件卸载或依赖变化前执行,用于清理副作用(如 return () => clearInterval(timer))。 空依赖数组时,仅在卸载时清理;若有依赖,依赖变化时也会先清理旧副作用。 |
场景 5:组件更新后执行操作(如根据新数据更新 DOM)
- 核心需求:组件因 props/state 变化重新渲染后,执行依赖新 DOM 的操作(如调整元素位置、更新第三方库配置)。
框架 / 范式 | 推荐 API / 生命周期函数 | 原因与注意事项 |
---|---|---|
Vue2(选项式) | updated | - 组件更新(DOM 重新渲染)后执行,此时可访问更新后的 DOM(如 this.$refs.list 的新内容),适合根据新数据调整 DOM(如滚动到指定位置)。注意:避免在其中修改数据(会触发再次更新,导致无限循环)。 |
Vue3(组合式) | onUpdated | 组件更新完成后执行,与 Vue2 的 updated 一致,可操作更新后的 DOM(需配合 ref 获取节点)。 |
React(类组件) | componentDidUpdate | - 组件更新后执行,需对比 prevProps/prevState(如 if (this.state.list !== prevState.list)),执行 DOM 操作(如滚动到列表底部)。 |
React(Hooks) | useEffect(() => { … }, [deps]) | 依赖更新后的数据(如 list),确保 DOM 已根据新数据更新,执行操作(如 listRef.current.scrollTop = listRef.current.scrollHeight)。依赖数组需包含触发更新的数据,确保更新后执行。 |
场景 6:错误处理(捕获组件内错误)
- 核心需求:捕获组件渲染或执行过程中的错误(如 API 请求失败、代码异常),避免整个应用崩溃。
框架 / 范式 | 推荐 API / 生命周期函数 | 原因与注意事项 |
---|---|---|
Vue2(选项式) | 无官方错误边界,需手动 try/catch | -Vue2 没有内置错误边界,需在可能出错的地方(如 API 请求、事件处理)用 try/catch 捕获,或通过全局配置 Vue.config.errorHandler 监听全局错误。 |
Vue3(组合式) | onErrorCaptured | 组件内捕获子组件的错误(如渲染错误、生命周期错误),返回 false 可阻止错误向上传播(避免影响父组件)。 配合全局 app.config.errorHandler 处理全局错误。 |
React(类组件) | componentDidCatch(error, info) | - 类组件作为错误边界,捕获子组件的渲染错误,可在 render 中返回备用 UI(如 return ),避免应用崩溃。 |
React(Hooks) | 需用类组件封装错误边界(Hooks 无原生支持) | React Hooks 本身不支持错误边界,需通过类组件包裹 Hooks 组件,用 componentDidCatch 捕获错误(React 的设计:错误边界必须是类组件)。 |
总结:Vue 与 React 的生命周期设计差异
- Vue:生命周期钩子更贴近 “组件生命周期阶段”(创建、挂载、更新、销毁),API 设计更直观(如 mounted 直接对应 DOM 挂载完成),且内置数据响应式系统(watch/computed),减少手动对比数据的工作。
- React:类组件的生命周期更强调 “组件状态变化的时机”(如 componentDidUpdate 对应每次更新后),Hooks 则用 useEffect 统一处理副作用(整合了挂载、更新、卸载的逻辑),更灵活但需手动管理依赖数组,避免冗余执行。