React中OptionList无选项显示:一个下拉列表无法正常填充
问题概述
尝试通过两个异步函数填充两个下拉列表,frames列表正常显示,nonFramesComponent列表无内容。调用填充函数时,nonFramesArr[0]打印为undefined,展开数组时提示“This value was evaluated upon first expanding, it may have changed since then”。
核心原因
1. 异步请求未等待,函数提前返回空数组
getSmbFrameNfts和getNonFrameNfts函数中,fetch是异步操作,但代码没有等待所有fetch完成就返回了数组。for循环里的fetch会并行执行,但函数会直接返回初始的空数组frames,后续fetch完成后才会往数组里push数据,但此时调用者已经拿到了空数组,导致后续遍历数组时长度为0,无法生成选项。
2. 函数名不匹配(代码笔误)
填充函数populateListsWithNfts中调用了getFrames()和getNonFrames(),但实际定义的函数是getSmbFrameNfts和getNonFrameNfts,函数名不匹配会导致调用错误(如果无其他别名处理)。
3. 多余的await使用
document.getElementById("nonFramesComponent").innerHTML = await nonFrameStr;中,nonFrameStr是字符串而非Promise,await完全多余,属于错误用法。
修复方案
步骤1:等待所有异步请求完成
收集所有fetch的Promise,用Promise.all统一等待,确保返回数组时已填充数据。
步骤2:修正函数名匹配
确保填充函数调用的函数名和定义一致,比如将getFrames()改为getSmbFrameNfts(),getNonFrames()改为getNonFrameNfts()。
步骤3:移除多余的await
去掉对字符串变量的await调用。
修复后的完整代码示例
// 获取FRAME类型NFT的函数 const getSmbFrameNfts = async () => { const connection = await new Connection('mainnet-beta'); const ownerPublicKey = walletAddress; const nftsmetadata = await Metadata.findDataByOwner(connection, ownerPublicKey); // 收集所有需要执行的fetch Promise const fetchPromises = []; for (const nft of nftsmetadata) { if (nft.data.symbol === 'FRAME') { fetchPromises.push( fetch(nft.data.uri).then(response => response.json()) ); } } // 等待所有fetch完成,返回结果数组 return Promise.all(fetchPromises); } // 获取非FRAME类型NFT的函数 const getNonFrameNfts = async () => { const connection = await new Connection('mainnet-beta'); const ownerPublicKey = walletAddress; const nftsmetadata = await Metadata.findDataByOwner(connection, ownerPublicKey); const fetchPromises = []; for (const nft of nftsmetadata) { if (nft.data.symbol !== 'FRAME') { fetchPromises.push( fetch(nft.data.uri).then(response => response.json()) ); } } return Promise.all(fetchPromises); } // 填充下拉列表的函数 const populateListsWithNfts = async () => { const frames = await getSmbFrameNfts(); const nonFramesArr = await getNonFrameNfts(); let frameStr = ''; let nonFrameStr = ''; for (const frame of frames) { frameStr += `<option value="${frame.name}">${frame.name}</option>`; } for (const nonFrame of nonFramesArr) { nonFrameStr += `<option value="${nonFrame.name}">${nonFrame.name}</option>`; } document.getElementById("nonFramesComponent").innerHTML = nonFrameStr; document.getElementById("frames").innerHTML = frameStr; }
额外优化点
- 使用
for...of循环替代for...in或索引循环,代码更简洁可读 - 修正选项标签格式:原自闭合标签
<option value="..."/>部分浏览器无法正确渲染,改为包含显示文本的闭合标签<option value="...">显示文本</option> - 可复用
Connection实例,避免重复创建提升性能
内容的提问来源于stack exchange,提问作者biccs

