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

React中如何在useEffect获取数据时批量执行多个setState?异步场景下避免多次重渲染的方案

为什么你的setState没有被批量处理?

你观察得很准——问题确实出在异步代码的执行时机上。让我拆解一下:

批量更新的规则

React的批量更新并不是在所有场景下都生效:

  • 在React同步上下文里(比如组件的事件处理函数、useEffect的同步回调块),多个setState会被合并成一次重渲染。
  • 但在异步回调(比如async/await后续的代码、Promise.then、setTimeout)里,React 17及更早版本不会自动批量处理setState,每调用一次setState就会触发一次重渲染。

你的代码里,setWorldData和setCountriesData是在await Promise.all()之后执行的,这属于异步回调的范畴,所以两次setState会分别触发重渲染:第一次是setWorldData更新后,组件重渲染,控制台输出获取到的worldData;第二次是setCountriesData更新后,组件再次重渲染,这时候worldData已经是最终值了,所以控制台又输出一次相同的数组。

解决方法:让组件只重渲染一次

有几种可靠的方式实现这个需求:

1. 合并多个state为一个对象

这是最推荐的方案,既符合React的状态管理思路,又能从根源上减少不必要的重渲染:

function App() {
  // 合并两个state为一个对象
  const [covidData, setCovidData] = useState({
    worldData: null,
    countriesData: null
  })

  useEffect(() => {
    const fetchData = async () => {
      try {
        const [countries, world] = await Promise.all([
          fetch("https://disease.sh/v3/covid-19/countries?yesterday=true").then(res => res.json()),
          fetch("https://disease.sh/v3/covid-19/all?yesterday=true").then(res => res.json())
        ])
        // 一次setState更新所有数据
        setCovidData({
          worldData: world,
          countriesData: countries
        })
      } catch (err) {
        console.log(err)
      }
    }
    fetchData();
  }, []);

  console.log(covidData.worldData);
}

这样只需要调用一次setCovidData,组件只会重渲染一次。

2. 手动触发批量更新(React 17及更早)

如果你不想合并state,可以使用React提供的unstable_batchedUpdates API(注意:它标记为不稳定,未来可能会有变动),手动把多个setState包裹在批量更新里:

import { unstable_batchedUpdates } from 'react-dom'; // 注意是react-dom而不是react

// ...

useEffect(() => {
  const fetchData = async () => {
    try {
      const [countries, world] = await Promise.all([
        fetch("https://disease.sh/v3/covid-19/countries?yesterday=true").then(res => res.json()),
        fetch("https://disease.sh/v3/covid-19/all?yesterday=true").then(res => res.json())
      ])
      
      unstable_batchedUpdates(() => {
        setWorldData(world)
        setCountriesData(countries)
      })
    } catch (err) {
      console.log(err)
    }
  }
  fetchData();
}, []);

3. 升级到React 18并使用createRoot

React 18引入了自动批量更新,不管是同步还是异步场景,都会自动合并多个setState。但要注意:这个特性只在使用createRoot渲染组件时生效,老的ReactDOM.render不会开启它。

比如你的入口文件应该改成:

import { createRoot } from 'react-dom/client';
import App from './App';

const root = createRoot(document.getElementById('root'));
root.render(<App />);

升级后,你的原代码里的两次setState会被自动批量处理,组件只会重渲染一次。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 06:57:30