如何按id匹配两个接口数据为循环渲染的ShiftComponent传参
核心问题说明
你当前的实现存在两个核心错误:
- 循环调用第二个API时,每次请求成功都直接执行
setValue(resp.data),会持续覆盖前一次的请求结果,最终value状态只会保留最后一个请求的返回值,无法存储所有id对应的数据 - 渲染时嵌套遍历两个数组会产生笛卡尔积,自然会出现重复渲染问题,大数据量场景下还会严重拖累性能
解决方案
步骤1:调整value状态的存储结构
把value从数组/单个对象改为以id为键的映射对象,可以实现O(1)时间的id匹配,适配大数据量场景的性能要求:
// 初始化状态时使用空对象 const [valueMap, setValueMap] = useState<Record<string | number, {name: string, address: {state: string, city: string}}>>({})
步骤2:优化第二个API的批量调用逻辑
使用Promise.all统一处理批量请求,避免循环调用的竞态问题,请求完成后一次性更新映射对象:
const fetchValueList = async () => { try { // 生成所有请求的Promise数组 const requestList = id.map(itemId => ApiCall.get(`${Url}value/${itemId}`)) // 等待所有请求完成 const respList = await Promise.all(requestList) // 把返回结果转换为id为键的映射对象 const resultMap = respList.reduce((map, resp) => { const data = resp.data map[data.id] = data return map }, {}) // 一次性更新状态 setValueMap(resultMap) } catch (err) { console.log(err) Alert.alert('Error', '数据获取失败') } }
如果需要兼容部分请求失败不影响整体使用的场景,可以将单个请求包一层错误捕获,把Promise.all替换为Promise.allSettled即可。
步骤3:渲染时直接匹配id取值
不需要嵌套遍历,直接用shift列表的item.id去映射对象中取对应数据即可:
{shift.map((item: any) => ( <ShiftComponent key={item.id} // 不要用index作为key,使用唯一id避免渲染异常 Name={valueMap[item.id]?.name || '默认名称'} StartTime={item.expected.start_time} EndTime={item.expected.end_time} Address={valueMap[item.id]?.address ? `${valueMap[item.id].address.city} ${valueMap[item.id].address.state}` : '默认地址'} /> ))}
如果需要避免数据加载过程中出现空值闪烁,可以额外加一个加载状态判断,等所有数据返回后再渲染组件。
内容的提问来源于stack exchange,提问作者pratteek shaurya
相关产品推荐
相关产品推荐

