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

React中如何在useEffect同步处理时添加加载状态

解决React中长任务加载指示器不显示的问题

你的代码里加载指示器没生效的核心原因是:同步的长任务阻塞了主线程。当你调用setIsLoading(true)后,React需要更新UI,但紧接着的长循环会霸占主线程,直到循环结束才会处理渲染更新——这时候isLoading已经被设回false了,所以加载状态根本没机会显示。

下面是修复后的代码,同时处理了竞态问题(比如用户连续点击按钮时,避免旧的任务覆盖新结果):

function App() {
  const [value1, setValue1] = useState(0);
  const [value2, setValue2] = useState(0);
  const [output, setOutput] = useState(0);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    // 初始状态(value1和value2都是0)不处理
    if (!value1 && !value2) {
      return;
    }

    let isCancelled = false;
    setIsLoading(true);

    // 把长任务放到异步队列里,让主线程先渲染加载状态
    setTimeout(() => {
      // 检查是否已被取消(比如用户又点了一次按钮,触发新的useEffect)
      if (isCancelled) return;

      // 模拟长耗时操作
      for (let i = 0; i < 1999999999; i++) {}
      const result = value1 + value2;

      // 更新结果并结束加载状态
      setOutput(result);
      setIsLoading(false);
    }, 0);

    // 清理函数:组件卸载或依赖变化时,标记当前任务已取消
    return () => {
      isCancelled = true;
      setIsLoading(false); // 取消后立即隐藏加载状态
    };
  }, [value1, value2]);

  return (
    <div>
      <button onClick={() => setValue1(value1 + 1)}>increment value1</button>
      <button onClick={() => setValue2(value2 + 1)}>increment value2</button>
      <div>
        {value1} + {value2} = {isLoading ? 'please wait...' : output}
      </div>
    </div>
  );
}

关键说明

  1. 异步执行长任务:用setTimeout把长任务包起来,哪怕延迟设为0,也会把任务放到浏览器的异步队列里,让主线程先完成React的UI更新(显示加载指示器),再执行耗时操作。
  2. 竞态条件处理:添加isCancelled标志,当用户连续点击按钮触发新的useEffect时,旧的任务会被标记为取消,避免旧的计算结果覆盖新的状态。
  3. 清理函数:组件卸载或者依赖项变化时,及时取消未完成的任务并隐藏加载状态,防止内存泄漏或无效的状态更新。

进阶方案(针对超耗时计算)

如果你的实际任务是计算密集型的(比如复杂数据处理),更推荐用Web Workers来处理,它能在独立线程中执行任务,完全不阻塞主线程,让页面保持响应。核心思路是:

  • 创建一个Worker文件处理计算逻辑
  • 在组件中发送数据给Worker,监听Worker返回的结果
  • 根据Worker的状态控制加载指示器

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:35:45