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

React中await使用错误致useState返回空数组,求技术排查

问题:useState变量返回空数组,await异步操作未正确等待

我已经连续两天排查问题,仍未找到await关键字的使用错误点。当前我的useState变量r返回空数组,且console.log在数据完成填充前就已执行,以下是完整代码实现:

useEffect(() => {
const main = async () => {
  const profileData = [];
  try {
    coll.map(async (col) => {
      const instance = new Contract(col, nftABI, provider);
      const balance = await instance.balanceOf(profile);
      let profileBalance = balance.toNumber();
      const tokenIds = [];
      const name = [];
      const images = [];
      for (let i = 0; i < profileBalance; i++) {
        if (profileBalance > 0) {
          console.log(profileBalance, i, col);
          const tokenId = await instance.tokenOfOwnerByIndex(profile, i);
          let NumTokenId = tokenId.toNumber();
          let StrTokenId = String(NumTokenId);
          const uri = await instance.tokenURI(StrTokenId);
          const url = uri.replace(
            "ipfs://",
            "https://gateway.pinata.cloud/ipfs/"
          );
          const ipfsFile = await fetch(url).then((r) => r.json());
          const imageUri = ipfsFile.image.replace(
            "ipfs://",
            "https://gateway.pinata.cloud/ipfs/"
          );
          name.push(ipfsFile.name);
          images.push(imageUri);
          tokenIds.push(StrTokenId);
        }
      }
      const obj = {
        collection: col,
        tokenArray: tokenIds,
        image: images,
        name: name,
      };
      if (obj.name.length > 0) {
        profileData.push(obj);
      }
    });
  } catch (error) {
    console.log(error);
  }
  setR(profileData);
};
main();
}, []);

核心错误原因

你在coll.map()里用了async回调函数,但没等待所有这些异步回调执行完就调用了setR(profileData)。map会直接返回一堆Promise,但你没处理这些Promise,导致main函数在所有异步操作完成前就走到了setR这一步,此时profileData还是空的。另外,外层的try/catch也抓不到map内部异步函数的错误,因为这些错误被封装在Promise里,没被等待的话不会冒泡到外层。

修复方案

  1. 用Promise.all()包裹map返回的Promise数组,确保所有异步任务完成后再更新状态:
    把coll.map(...)改成:

    await Promise.all(coll.map(async (col) => {
      // 原有异步逻辑不变
    }));
    

    这样main会等所有异步操作做完,再执行setR,此时profileData已经被正确填充。

  2. 把fetch的.then()写法改成await风格,保持代码一致性:

    const response = await fetch(url);
    const ipfsFile = await response.json();
    
  3. 可选优化:把profileBalance > 0的判断移到循环外面,避免每次循环重复判断。

修复后的完整代码

useEffect(() => {
  const main = async () => {
    const profileData = [];
    try {
      // 等待所有map内的异步任务完成
      await Promise.all(coll.map(async (col) => {
        const instance = new Contract(col, nftABI, provider);
        const balance = await instance.balanceOf(profile);
        let profileBalance = balance.toNumber();
        const tokenIds = [];
        const name = [];
        const images = [];
        
        // 把判断移到循环外,减少重复执行
        if (profileBalance > 0) {
          for (let i = 0; i < profileBalance; i++) {
            console.log(profileBalance, i, col);
            const tokenId = await instance.tokenOfOwnerByIndex(profile, i);
            let NumTokenId = tokenId.toNumber();
            let StrTokenId = String(NumTokenId);
            const uri = await instance.tokenURI(StrTokenId);
            const url = uri.replace(
              "ipfs://",
              "https://gateway.pinata.cloud/ipfs/"
            );
            // 改用await风格处理fetch
            const response = await fetch(url);
            const ipfsFile = await response.json();
            const imageUri = ipfsFile.image.replace(
              "ipfs://",
              "https://gateway.pinata.cloud/ipfs/"
            );
            name.push(ipfsFile.name);
            images.push(imageUri);
            tokenIds.push(StrTokenId);
          }
        }
        
        const obj = {
          collection: col,
          tokenArray: tokenIds,
          image: images,
          name: name,
        };
        if (obj.name.length > 0) {
          profileData.push(obj);
        }
      }));
    } catch (error) {
      console.log(error);
    }
    setR(profileData);
  };
  main();
}, []);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 16:00:26