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

useTransition的isPending未等待API调用完成就变为false的问题求助

useTransition的isPending未等待API调用完成就变为false的问题求助

我正在尝试解决useTransition钩子的问题。我有一个按钮,点击它会触发一个发起API调用的函数。问题在于useTransition返回的isPending在API调用完成前就被设置为false了。

以下是我的代码:

function App() {
  const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
  const [isPending, startTransition] = useTransition();
  const [data, setData] = useState(null);
  useEffect(()=>{
    console.log("Is Pending changed", isPending)
  },[isPending])
  const fetchData = async () => {
    startTransition(async () => {
      await delay(2000);
      const response = await fetch('https://jsonplaceholder.typicode.com/todos/1'); // Replace with your API endpoint
      const result = await response.json();
      setData(result);
    });
  };

  return (
    <div>
      <button onClick={fetchData}>Fetch Data</button>
      {isPending ? (
        <p>Fetching data...</p>
      ) : (
        data && <pre>{JSON.stringify(data, null, 2)}</pre>
      )}
    </div>
  );

}

我原本期望useTransition会像文档里说的那样等待API调用完成,是不是我哪里用错了?


嘿,我来帮你捋清楚这个问题!问题的核心是你对useTransition的作用理解有点偏差——它并不是用来跟踪异步请求加载状态的工具,而是用来标记状态更新的优先级,让React知道某些状态更新可以延迟执行,优先响应用户的交互(比如点击、输入操作)。

具体到你的代码,startTransition接受的是一个同步函数,它只会跟踪这个同步函数执行过程中触发的状态更新。你把异步函数传给它之后,startTransition会立刻执行完这个异步函数的同步阶段(也就是进入await delay(2000)之前的代码),然后就认为过渡已经结束了,所以isPending马上就变成了false。而后面的API请求和setData都是在异步任务里执行的,这时候过渡早就结束了,自然不会再触发isPending的变化。

那该怎么调整呢?分两种场景给你方案:

场景1:想用isPending跟踪状态更新的过渡(而非API请求加载)

如果你的API请求本身很快,只是setData之后的渲染可能比较耗时,那应该把异步请求放在startTransition外面,等数据拿到后再用startTransition包裹状态更新:

function App() {
  const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
  const [isPending, startTransition] = useTransition();
  const [data, setData] = useState(null);
  // 自己维护一个状态跟踪API请求的加载
  const [loading, setLoading] = useState(false);

  useEffect(()=>{
    console.log("Is Pending changed", isPending)
  },[isPending])

  const fetchData = async () => {
    setLoading(true);
    try {
      await delay(2000);
      const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
      const result = await response.json();
      // 拿到数据后,用startTransition包裹状态更新
      startTransition(() => {
        setData(result);
      });
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <button onClick={fetchData}>Fetch Data</button>
      {/* 用loading显示API加载状态,isPending显示状态更新的过渡 */}
      {loading || isPending ? (
        <p>Fetching data...</p>
      ) : (
        data && <pre>{JSON.stringify(data, null, 2)}</pre>
      )}
    </div>
  );
}

场景2:想让加载状态覆盖整个API请求过程

如果你的核心需求是在API请求的整个过程中显示加载状态,那useTransition其实不是合适的工具,直接自己维护一个loading状态就够了,useTransition可以用来优化状态更新时的UI体验(比如避免渲染卡顿):

function App() {
  const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
  const [isPending, startTransition] = useTransition();
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  const fetchData = async () => {
    setLoading(true);
    try {
      await delay(2000);
      const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
      const result = await response.json();
      // 如果渲染数据时可能卡顿,就用startTransition包裹
      startTransition(() => {
        setData(result);
      });
    } catch (err) {
      console.error('请求出错:', err);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <button onClick={fetchData}>Fetch Data</button>
      {loading ? (
        <p>Fetching data...</p>
      ) : isPending ? (
        <p>Processing data...</p>
      ) : (
        data && <pre>{JSON.stringify(data, null, 2)}</pre>
      )}
    </div>
  );
}

总结一下:useTransition的isPending只跟踪同步回调里的状态更新,异步操作的加载状态需要自己用useState来维护哦!

备注:内容来源于stack exchange,提问作者Vaibhav Tiwari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 18:19:30