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里,没被等待的话不会冒泡到外层。
修复方案
用
Promise.all()包裹map返回的Promise数组,确保所有异步任务完成后再更新状态:
把coll.map(...)改成:await Promise.all(coll.map(async (col) => { // 原有异步逻辑不变 }));这样
main会等所有异步操作做完,再执行setR,此时profileData已经被正确填充。把
fetch的.then()写法改成await风格,保持代码一致性:const response = await fetch(url); const ipfsFile = await response.json();可选优化:把
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
相关产品推荐
相关产品推荐

