You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中不使用useEffect Hook的代码可行,是否建议采用?

关于React useEffect的必要性解答

你的代码现在能“正常运行”只是表面现象,实际上存在严重问题,绝对不能省略useEffect,你忽略了React组件的渲染机制和副作用管理的核心逻辑——哪怕是小型场景,也不能这么写,具体原因如下:

  • 不必要的重复请求:React组件函数会在每次状态更新(比如setTitle、setNum)、父组件重渲染、props变化时重新执行。把fetch直接写在组件函数里,意味着这些场景都会触发新的网络请求——比如setTitle更新title状态时,组件会再次渲染,又会发起一次相同的请求,纯粹是资源浪费。

  • 竞态风险:如果快速点击按钮多次,多个fetch请求会同时发出,而响应的返回顺序可能和请求顺序不一致。比如你先请求num=3,再请求num=4,但num=3的响应晚于num=4返回,最终title会被旧数据覆盖,导致显示错误。

  • useEffect的核心作用:它的存在就是为了让你精准控制副作用(比如网络请求、DOM操作、定时器等)的执行时机。在你的场景里,你只希望当num变化时才发起请求,所以必须把fetch放进useEffect,并将num加入依赖数组,这样只有num改变时才会执行这个副作用。

修正后的代码(加入请求取消逻辑,彻底避免竞态问题):

import { useState, useEffect } from 'react';

export default function App() {
  const [title, setTitle] = useState(null);
  const [num, setNum] = useState(2);

  useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;

    fetch(`https://jsonplaceholder.typicode.com/todos/${num}`, { signal })
      .then((response) => response.json())
      .then((response) => {
        setTitle(response.title);
      })
      .catch(err => {
        // 忽略请求被取消的错误
        if (err.name !== 'AbortError') throw err;
      });

    // 组件卸载或num变化时,取消未完成的请求
    return () => controller.abort();
  }, [num]);

  return (
    <div className="App">
      <h1>useEffect Example</h1>
      <pre>{title}</pre>
      <button onClick={() => setNum(num + 1)}>Increment</button>
    </div>
  );
}

总结:不管场景大小,直接在组件函数内写副作用都是违背React设计理念的写法,会导致不可预测的行为,必须用useEffect来管理这类操作。

内容的提问来源于stack exchange,提问作者Nesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:00:24