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

React中useEffect无限循环原因分析及startTransition相关疑问

React中useEffect无限循环原因分析及startTransition相关疑问

首先来看你的代码:

index.jsx

const { startTransition, useEffect, useState } = React;
const { createRoot } = ReactDOM;

function App() {
  const [foo, setFoo] = useState([1]);
  const [bar, setBar] = useState("1");

  useEffect(() => {
    console.log("infinite loop")
    setBar(() => {
      console.log("bar");
      return "2";
    })
  }, [foo]);

  return (
    <>
      <button
        onClick={() => {
          startTransition(() => {
            setFoo((foo)=>{
              console.log("transition");
              return [];
            });
          });
          setFoo((foo) => { 
            console.log("foo");
            return [];
          });
        }}
      >
        example
      </button>
    </>
  );
}

createRoot(document.getElementById("container")).render(<App />);

HTML部分

<div id="container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.0/umd/react-dom.production.min.js"></script>

无限循环的原因分析

当你点击按钮时,会触发两个setFoo操作:一个是包裹在startTransition里的过渡更新,另一个是直接调用的同步紧急更新。

同步的setFoo会优先执行,把foo从[1]改成[],触发组件重新渲染。此时useEffect的依赖foo发生了变化,所以会执行useEffect回调——里面调用了setBar更新bar状态,这又会触发一次组件重新渲染。

问题就出在这里:在React 18的更新机制下,当存在pending的过渡更新(也就是startTransition里的setFoo)时,每次setBar触发的渲染都会让React重新检查状态依赖,导致useEffect被反复触发(尽管foo看起来没有变化),进而形成无限循环。而因为这个循环一直没停下来,startTransition里的代码根本没机会执行,所以你看不到"transition"的日志。

你提到的两种解决方法也印证了这个逻辑:

  • 删除setBar:没有了额外的状态更新触发渲染,循环自然终止,过渡更新也能正常执行
  • 删除startTransition:没有了pending的过渡更新,setBar触发的渲染不会再反复触发useEffect,循环也就停止了

关于startTransition的简单介绍

startTransition是React 18新增的API,核心作用是标记非紧急更新,让React优先处理紧急更新(比如用户输入、同步状态变更这类会直接影响UI交互的操作),把非紧急更新推迟到紧急更新完成后再处理。

举个常见的场景:在搜索框输入关键词时,输入操作是紧急更新(必须立刻响应,不然用户会觉得卡顿),而根据关键词请求搜索结果并更新列表的操作就是非紧急的——把这个更新放到startTransition里,就能保证输入流畅,同时后台默默加载搜索结果。

用startTransition包裹的更新会被标记为“过渡中”,React会允许这类更新被中断,如果有新的紧急更新进来,会先处理紧急的,避免UI阻塞。

备注:内容来源于stack exchange,提问作者pistol magic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 09:53:07