useEffect 中Clean up 函数的执行机制

引言 💭

在 React 中,useEffect 的清理函数(cleanup)是副作用管理的关键机制。首次挂载时它不会执行,而是在依赖更新或组件卸载时才触发,遵循一套严格的执行顺序。


1. Cleanup 函数的本质

useEffectreturn 清理函数用于清除上一次渲染产生的副作用,而不是当前渲染的副作用。

  • 首次渲染:没有上一次副作用,因此不执行 cleanup。
  • 更新或卸载:React 会先执行 cleanup,再运行新的副作用逻辑。

2. 核心执行机制

① 首次渲染(挂载)

  • 执行 effect 函数
  • 不执行 cleanup(因为没有旧副作用)

② 依赖项更新

执行顺序:

  1. 执行上一次的 cleanup(清理旧副作用)
  2. 执行新的 effect(注册新副作用)

③ 组件卸载

  • 仅执行 cleanup,用于释放最后的副作用

3. 示例代码

javascript 复制代码
function Example({ prop }) {
  useEffect(() => {
    console.log("Effect 执行");
    return () => {
      console.log("Cleanup 执行");
    };
  }, [prop]);

  return <div>Example</div>;
}

4. 与类组件对比

useEffect 的清理机制相当于类组件中两个生命周期方法的组合:

  • 首次挂载 :类似 componentDidMount(只执行 effect)。
  • 更新/卸载 :先 componentWillUnmount(清理),再 componentDidUpdate(运行新 effect)。

5. 为什么要这样设计?

  1. 避免无意义清理:首次渲染时没有旧副作用。
  2. 保持逻辑一致:始终清理"上一次"的副作用。
  3. 性能优化:减少额外的函数调用。

6. 运行验证

javascript 复制代码
import { useEffect, useState } from "react";

function Demo() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("Effect 运行,count =", count);
    return () => {
      console.log("Cleanup 运行,count =", count);
    };
  }, [count]);

  return <button onClick={() => setCount(count + 1)}>点击 {count}</button>;
}

输出顺序:

  1. 首次渲染

    ini 复制代码
    Effect 运行,count = 0
  2. 点击按钮(count → 1)

    ini 复制代码
    Cleanup 运行,count = 0
    Effect 运行,count = 1
  3. 卸载组件

    ini 复制代码
    Cleanup 运行,count = 1

7. 特殊情况:严格模式(Strict Mode)

开发模式 下,React 会故意执行一次"挂载 → 卸载 → 重新挂载",以检测副作用是否安全:

arduino 复制代码
Effect 运行   // 挂载
Cleanup 运行 // 卸载
Effect 运行   // 重新挂载

⚠️ 这只是开发阶段的调试行为,生产环境不会发生。


8. 关键特性

  1. cleanup 永远对应上一次 effect

  2. 执行时机在浏览器绘制后(异步)

  3. 多个 effect 的执行顺序

    • effect:按定义顺序执行
    • cleanup:按相反顺序执行
javascript 复制代码
useEffect(() => { /* effect 1 */ return () => { /* cleanup 1 */ } });
useEffect(() => { /* effect 2 */ return () => { /* cleanup 2 */ } });

// 执行顺序:effect1 → effect2 → cleanup2 → cleanup1

总结✒️

场景 是否执行 cleanup 原因
首次挂载 ❌ 否 没有旧副作用
依赖项变化 ✅ 是 清理旧副作用,再注册新副作用
组件卸载 ✅ 是 清理最后一个副作用
严格模式(开发) ✅ 可能两次 React 故意测试卸载逻辑

return 清理函数始终是滞后执行的 :它清理的是上一次的副作用,而不是当前的。

相关推荐
2601_949593653 分钟前
React Native 鸿蒙跨平台开发:LinearGradient 渐变动画效果
javascript·react native·react.js
黄筱筱筱筱筱筱筱5 分钟前
7.适合新手小白学习Python的异常处理(Exception)
java·前端·数据库·python
qq_177767376 分钟前
React Native鸿蒙跨平台音乐播放器涉及实时进度更新、播放控制、列表交互、状态管理等核心技术点
javascript·react native·react.js·ecmascript·交互·harmonyos
2501_920931709 分钟前
React Native鸿蒙跨平台实现了简单的商品图片轮播功能,为用户提供了直观的商品图片浏览体验,帮助用户全面了解商品外观
javascript·react native·react.js·ecmascript·harmonyos
Yeats_Liao12 分钟前
微调决策树:何时使用Prompt Engineering,何时选择Fine-tuning?
前端·人工智能·深度学习·算法·决策树·机器学习·prompt
晚霞的不甘12 分钟前
Flutter for OpenHarmony 实现 iOS 风格科学计算器:从 UI 到表达式求值的完整解析
前端·flutter·ui·ios·前端框架·交互
陈希瑞15 分钟前
OpenClaw Chrome扩展使用教程 - 浏览器中继控制
前端·chrome
2501_9219308317 分钟前
React Native 鸿蒙跨平台开发:LinearGradient 线性渐变详解
react native·react.js·harmonyos
雨季66620 分钟前
Flutter 三端应用实战:OpenHarmony “呼吸灯”——在焦虑时代守护每一次呼吸的数字禅修
开发语言·前端·flutter·ui·交互
切糕师学AI21 分钟前
Vue 中如何修改地址栏参数并重新加载?
前端·javascript·vue.js