聊聊useEffect:谁说副作用不能“优雅”?

作为一名前端工程师,我和useEffect的"爱恨情仇"简直能写一部连续剧。从最初觉得它"难以驯服",到如今逐渐摸清它的脾气,我花了不止一丢丢时间。今天就来聊聊这个React中最常用却又容易被误解的Hook------useEffect,以及它背后的"副作用"哲学。


一、什么是副作用?先别慌,没那么复杂!

很多人一听到"副作用"就想到"bug"或"不可控",但其实在编程中,副作用(Side Effect)指的是函数或组件在执行过程中,与外部世界发生的交互。比如:

  • 数据获取(API调用)
  • 手动修改DOM
  • 订阅事件
  • 设置定时器

这些操作都可能影响其他组件或全局状态,所以React把它们统称为"副作用"。而useEffect,就是React为我们提供的"副作用管理工具"。


二、useEffect:副作用的"安全屋"

useEffect的核心思想是:把副作用操作从主渲染逻辑中剥离出来,放到一个独立的空间去执行。这样既能保持组件的纯净性,又能灵活处理各种边界场景。

基本用法:

jsx 复制代码
import { useEffect, useState } from 'react';

function MyComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    // 副作用逻辑:数据获取
    fetch('https://api.example.com/data')
      .then(res => res.json())
      .then(data => setData(data));
  }, []); // 依赖数组为空,表示只在挂载时执行一次

  return <div>{data ? data.message : 'Loading...'}</div>;
}

三、依赖数组:useEffect的"开关控制器"

useEffect的第二个参数(依赖数组)决定了它何时执行。这里有几个经典场景:

1. 每次渲染都执行(不传依赖数组)

jsx 复制代码
useEffect(() => {
  console.log('我每次渲染都会跑一遍!');
});

2. 只执行一次(传空数组)

jsx 复制代码
useEffect(() => {
  console.log('我只在组件挂载时执行一次');
}, []);

3. 依赖变化时执行

jsx 复制代码
useEffect(() => {
  console.log('count变了,我得重新跑!');
}, [count]);

四、 cleanup:别忘了我!

如果副作用需要清理(比如取消订阅、清除定时器),useEffect允许返回一个清理函数:

jsx 复制代码
useEffect(() => {
  const timer = setInterval(() => {
    console.log('每秒蹦跶一次');
  }, 1000);

  return () => {
    clearInterval(timer); // 组件卸载时清理
  };
}, []);

五、实战坑点:我踩过的那些雷

  1. 无限循环

    在useEffect中修改依赖项的状态,且未正确设置依赖数组:

    jsx 复制代码
    // 错误示范:setCount会导致重新渲染,重新渲染又触发useEffect......
    useEffect(() => {
      setCount(count + 1);
    }, [count]);
  2. 闭包陷阱

    在定时器或事件监听中访问到旧的state值:

    jsx 复制代码
    useEffect(() => {
      const timer = setInterval(() => {
        console.log(count); // 永远是最初的count值
      }, 1000);
      return () => clearInterval(timer);
    }, []);

    解决方法:用useRef保存最新值,或通过函数式更新避免依赖。


六、总结:useEffect是副作用的"管家"

它不会让副作用消失,但能帮我们把它管得明明白白。记住几个关键点:

  • 分离关注点:渲染逻辑和副作用逻辑分开。
  • 控制执行时机:依赖数组是灵魂。
  • 及时清理:避免内存泄漏。

最后送大家一句话: "用useEffect不是为了避免副作用,而是为了让它变得更可控。" ------ 来自一个被副作用折磨过无数遍的前端工程师。

⭐ 写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

✅ 一起探讨技术加qq交流群:906392632

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

相关推荐
别惊醒渔人1 小时前
Vue3 Diff 优化:最长递增子序列 LIS
前端·javascript·vue.js
颜酱1 小时前
07 | 把字段与指标同步到 Qdrant(生成阶段)
前端·人工智能·后端
用户059540174461 小时前
把AI长期记忆测试从手动验证换成pytest,2天揪出11个隐藏Bug
前端·css
Larcher2 小时前
从“加载模型”界面到端侧推理:拆解一个 React + WebGPU 大模型 Demo
javascript·后端
Larcher2 小时前
从状态快照到惰性初始化:读懂 React useState 的三个关键场景
javascript·人工智能·后端
lichenyang4532 小时前
从 Vite 空项目到 AIGC 图片工作台:我如何打通生图、任务轮询、生成库与 Canvas 动态特效
前端·人工智能
泡沫冰@3 小时前
上章节中文件的讲解
前端·网络·nginx
进击的丸子3 小时前
APP人脸识别增值版Harmony Demo实操与关键代码解析
前端·程序员·harmonyos
a1117763 小时前
唯美花朵风格的黑胶唱片音乐播放器
前端·css·css3
Hilaku4 小时前
工作 5 年后,决定你薪资上限的究竟是什么?
前端·javascript·程序员