💓 博客主页:瑕疵的CSDN主页
📝 Gitee主页:瑕疵的gitee主页
⏩ 文章专栏:《热点资讯》

useEffect依赖漏写?别让组件在深夜疯狂重渲染!

昨天改个需求,组件突然像中了邪一样疯狂重渲染。控制台刷屏“useEffect执行”,UI卡得像PPT。我盯着代码,手抖得差点把咖啡泼在键盘上。

报错现场

function UserList() {
  const [users, setUsers] = useState([]);
  const fetchData = () => {
    // 模拟API请求
    setTimeout(() => setUsers([{ id: 1, name: '张三' }]), 500);
  };

  // 错误写法:依赖数组漏了fetchData
  useEffect(() => {
    fetchData();
  }, []); // 你以为这里安全?大错特错!

  return <div>{users.map(u => u.name)}</div>;
}

结果:每次状态变化(比如组件挂载后),fetchData都重新执行。数据重复请求,UI反复刷新。

核心根源
React的useEffect依赖数组是防抖开关。漏写依赖项,React会认为“每次渲染都有新数据”,强制重执行effect。
这里fetchData在effect内部定义,但依赖数组是空的。React不会跟踪fetchData的变化,所以每次渲染都当新函数处理。

对比代码

// 错误:依赖数组空,但用到了外部函数
useEffect(() => {
  fetchData(); // 依赖了fetchData,但没写进数组
}, []); // 每次渲染都触发

// 正确:依赖数组包含所有外部变量
useEffect(() => {
  fetchData(); // 依赖了fetchData
}, [fetchData]); // 必须加!

关键修复
把effect里用到的所有外部变量塞进依赖数组。这里fetchData是函数,必须显式声明:

// 修正后:依赖数组包含fetchData
useEffect(() => {
  fetchData();
}, [fetchData]); // 拼命提醒自己:别漏!

避坑总结

  1. ESLint是救命稻草:装eslint-plugin-react-hooks,exhaustive-deps规则会直接报错。

    npm install eslint-plugin-react-hooks --save-dev

  1. 写effect前先问自己:
    “这个effect里用了哪些外部变量?”(比如data、fetchData、userId)
    一个不漏,全塞进数组。
  2. 空数组不是万能:
    useEffect(() => {...}, [])只用于初始化请求(比如挂载时加载数据)。
    如果用了data,必须写[data],否则重复请求。
  3. 临时方案别乱用:
    有人写useEffect(() => {...}, [someVar])但someVar可能为undefined。
    用useRef存函数:

    const fetchDataRef = useRef(fetchData);
    fetchDataRef.current = fetchData; // 保持最新
    
    useEffect(() => {
      fetchDataRef.current();
    }, []);
    

最后吐个槽:这依赖数组坑我三次了。昨天debug到三点,发现是漏了fetchData。别信“依赖数组空就安全”——React不骗人,它只是太诚实。下次写前,先在注释里写:
// 依赖:fetchData(别漏!)

记住:useEffect不是自动防抖,是手动防抖。你漏了,它就疯狂刷。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐