useEffect的清理函数的执行时机

useEffect 的清理函数是 React 中管理副作用生命周期的关键机制,其执行时机遵循以下规则:

1. 核心执行时机

  • 组件卸载时:清理函数在组件从 DOM 中移除前执行,防止内存泄漏(如取消订阅、清除定时器)。
  • 副作用重复执行前 :如果 useEffect 因依赖项变化而重新执行,上一次 副作用的清理函数会在新副作用执行前触发。

2. 详细执行流程

首次渲染

  1. 组件渲染完成
  2. 执行 useEffect 中的副作用函数(不执行清理函数)

后续更新(依赖项变化时)

  1. 组件重新渲染
  2. 执行上一次副作用的清理函数
  3. 执行新的副作用函数

组件卸载

  1. 执行最后一次副作用的清理函数

3. 示例说明

jsx 复制代码
const Example = ({ value }) => {
  useEffect(() => {
    const subscription = api.subscribe(value);
    
    return () => {
      subscription.unsubscribe(); // 清理函数
    };
  }, [value]); // 依赖项:value 变化时重新执行

  return <div>Listening to {value}</div>;
};
  • 首次渲染value = "A"

    1. 组件渲染 <div>Listening to A</div>
    2. 执行 subscribe("A")
  • 更新后value = "B"

    1. 组件重新渲染 <div>Listening to B</div>
    2. 执行上一次的清理函数:unsubscribe("A")
    3. 执行新的副作用:subscribe("B")
  • 组件卸载

    1. 执行最后一次清理函数:unsubscribe("B")

4. 特殊场景说明

依赖项为空数组 []

清理函数仅在组件卸载时执行(相当于 componentWillUnmount):

jsx 复制代码
useEffect(() => {
  const timer = setInterval(() => console.log("Tick"), 1000);
  return () => clearInterval(timer); // 仅卸载时执行
}, []);

无依赖项数组

每次渲染都会执行副作用和清理函数(慎用,可能导致性能问题):

jsx 复制代码
useEffect(() => {
  // 每次渲染都执行
  return () => {
    // 每次重新渲染前都清理
  };
});

5. 注意事项

  1. 异步清理:清理函数必须是同步的(不能返回 Promise)。若需异步操作,可在清理函数中触发状态更新:

    jsx 复制代码
    useEffect(() => {
      let isMounted = true;
      fetchData().then(data => {
        if (isMounted) setData(data);
      });
      return () => (isMounted = false); // 同步标记组件已卸载
    }, []);
  2. 严格模式(开发环境) :React 18 在开发环境会额外调用一次清理函数和副作用,用于检测潜在问题,但生产环境不会。

总结

清理函数的核心作用是确保副作用的影响被正确撤销。通过在组件卸载前和副作用重复执行前执行清理,React 保证了资源的正确释放和状态的一致性。理解这一点对于避免内存泄漏和竞态条件至关重要。

相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95271 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大1 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师1 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学1 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端