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

React中useState在await方法内无法更新的问题求助

问题:React状态更新不生效,多次请求后state仍为空

我尝试通过多次GET请求获取宝可梦数据数组,将接口返回的response.data存入pokemonTeam状态变量,但始终无法生效。每次控制台打印pokemonTeam都显示为空数组,不过接口能正常返回正确数据。

原代码如下:

const [pokemonTeam, setPokemonTeam] = useState([]);

const generatePokemon = async () => {
    setPokemonTeam([]);
    const pokemonIDs = [];

    do {
      const randomID = Math.floor(Math.random() * 121);

      if (!pokemonIDs.includes(randomID)) {
        pokemonIDs.push(randomID);
      }
    } while (pokemonIDs.length < 6); //max 6 pokemon only
    let promises = [];
    for (var i = 0; i < pokemonIDs.length; i++) {
      promises.push(
        await axios
          .get(`https://pokeapi.co/api/v2/pokemon/${pokemonIDs[i]}/`)
          .then((res) => {
            setPokemonTeam([...pokemonTeam, res.data]);
            console.log(res.data);
            console.log(pokemonTeam);
          })
          .catch((err) => {
            console.log(err);
          })
      );
    }
    Promise.all(promises);
    console.log(pokemonTeam);
  };

问题原因分析

  1. 闭包导致state值过时:在then回调里的pokemonTeam是函数创建时的闭包值,始终为初始空数组。所以每次执行setPokemonTeam([...pokemonTeam, res.data]),都是把当前请求的数据加到空数组里,最终state只会保留最后一条请求的数据;再加上React状态更新是异步的,打印时更新还未完成,所以控制台显示为空。
  2. 错误使用await和Promise.all:循环内用await会让请求串行执行,且promises数组中存入的是请求的返回值(而非Promise对象),Promise.all(promises)没有加await,代码会直接执行最后的console.log(pokemonTeam),此时state还未完成更新。

修正方案

方案1:并行请求后一次性更新(推荐,性能更优)

先并行发起所有请求,等全部完成后一次性更新state,避免闭包和异步问题:

const [pokemonTeam, setPokemonTeam] = useState([]);

const generatePokemon = async () => {
    setPokemonTeam([]);
    const pokemonIDs = [];

    // 生成6个不重复的随机ID
    do {
        const randomID = Math.floor(Math.random() * 121);
        if (!pokemonIDs.includes(randomID)) {
            pokemonIDs.push(randomID);
        }
    } while (pokemonIDs.length < 6);

    try {
        // 并行创建所有请求Promise
        const requestPromises = pokemonIDs.map(id => 
            axios.get(`https://pokeapi.co/api/v2/pokemon/${id}/`)
        );
        // 等待所有请求完成
        const responses = await Promise.all(requestPromises);
        // 提取所有数据并更新state
        const pokemonData = responses.map(res => res.data);
        setPokemonTeam(pokemonData);
        console.log(pokemonData); // 此处可查看完整数据
    } catch (err) {
        console.error('请求失败:', err);
    }
};

方案2:函数式更新处理闭包(适用于需串行请求场景)

如果必须串行请求,使用函数式更新获取最新state,避免闭包陷阱:

const [pokemonTeam, setPokemonTeam] = useState([]);

const generatePokemon = async () => {
    setPokemonTeam([]);
    const pokemonIDs = [];

    do {
        const randomID = Math.floor(Math.random() * 121);
        if (!pokemonIDs.includes(randomID)) {
            pokemonIDs.push(randomID);
        }
    } while (pokemonIDs.length < 6);

    try {
        for (const id of pokemonIDs) {
            const res = await axios.get(`https://pokeapi.co/api/v2/pokemon/${id}/`);
            // 用函数式更新,确保拿到最新的state
            setPokemonTeam(prevTeam => [...prevTeam, res.data]);
        }
    } catch (err) {
        console.error('请求失败:', err);
    }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 21:18:22