React获取IoT设备影子时组件渲染后数据消失问题排查
问题核心原因
你的代码存在两个关键疏漏,直接导致渲染异常:
- 异步时序错误:
getShadows函数没有等待所有设备影子请求完成就提前返回了空的结果数组,后续请求返回后才往数组里push数据,属于典型的异步逻辑竞态 - 容错缺失:原生
Promise.all只要任意一个子请求失败(比如某台设备没有创建影子、接口权限不足、网络波动)就会整体抛出未捕获异常,打断React的状态更新流程,导致已经渲染的内容被清空
具体逻辑拆解
你原来的代码执行顺序是这样的:
- 等待
ListThingsCommand返回设备列表,这一步逻辑正常 - 批量发起所有设备的影子请求,给
Promise.all挂载了数据处理的回调,但没有用await等待这个Promise执行完成 - 同步返回初始化时的空数组
devices_list,React拿到空数组触发第一次状态更新 - 后续影子请求陆续返回,往你之前返回的数组引用里push数据,此时页面会短暂渲染出部分已返回的设备
- 只要某一个影子请求失败,
Promise.all直接抛出未捕获异常,整个状态更新流程中断,页面数据清空
这也是为什么你去掉影子请求逻辑、只返回设备列表时页面正常——那套逻辑是全程await等待结果返回后才return,没有时序问题,也不会因为子请求失败导致整体崩溃。
修复方案
- 去掉多余的手动Promise包装,给单个影子请求加错误兜底,避免单设备请求失败拖垮整个列表
- 用
await等待Promise.all全部执行完成后,再返回组装好的完整数组,不要提前返回空数组引用 - 给外层调用加异常捕获,避免未捕获错误打断渲染
- 增加可选链判断,避免影子数据结构不完整时触发JS报错
修复后的完整代码:
async function getShadows() { const listThings_command = new ListThingsCommand({}); const data = await iotClient.send(listThings_command); const things = data.things; // 单个设备影子请求独立做错误兜底 const shadowRequests = things.map(async (thing) => { try { const getThingShadow_command = new GetThingShadowCommand({thingName: thing.thingName}); const shadowRes = await iotDataPlaneClient.send(getThingShadow_command); const string_data = new TextDecoder('utf-8').decode(shadowRes.payload); const shadow_data = JSON.parse(string_data); return { thingName : thing.thingName, thingTypeName: thing.thingTypeName, thingArn : thing.thingArn, shadow : shadow_data.state?.reported // 可选链避免reported不存在时报错 }; } catch (err) { console.error(`获取设备[${thing.thingName}]影子失败:`, err); // 请求失败时保留设备基础信息,shadow字段置空,不阻塞整体渲染 return { thingName : thing.thingName, thingTypeName: thing.thingTypeName, thingArn : thing.thingArn, shadow : null } } }) // 等待所有请求执行完成,再返回最终组装的数组 const devices_list = await Promise.all(shadowRequests); return devices_list; }; function Home (){ const [mydevices, updateMydevices] = React.useState([]); useEffect(() => { getShadows() .then(data => updateMydevices(data)) .catch(err => console.error('设备列表加载失败:', err)); // 增加全局异常捕获 }, []); return ( <div className="App"> <h1>Dashboard</h1> <div> <h4>Devices List</h4> <ListGroup id="device_list"> { mydevices.map((device) => { return ( // 用设备唯一标识thingName当key,比用数组索引更稳定 <ListGroup.Item key={device.thingName}> <div>{device.thingName} </div> </ListGroup.Item> ) }) } </ListGroup> </div> </div> ); }
额外优化:列表渲染的key从数组索引换成了设备唯一标识
thingName,避免列表顺序变化时React渲染复用出错。
内容的提问来源于stack exchange,提问作者mvp
相关产品推荐
相关产品推荐

