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

React获取IoT设备影子时组件渲染后数据消失问题排查

问题核心原因

你的代码存在两个关键疏漏,直接导致渲染异常:

  • 异步时序错误:getShadows函数没有等待所有设备影子请求完成就提前返回了空的结果数组,后续请求返回后才往数组里push数据,属于典型的异步逻辑竞态
  • 容错缺失:原生Promise.all只要任意一个子请求失败(比如某台设备没有创建影子、接口权限不足、网络波动)就会整体抛出未捕获异常,打断React的状态更新流程,导致已经渲染的内容被清空

具体逻辑拆解

你原来的代码执行顺序是这样的:

  1. 等待ListThingsCommand返回设备列表,这一步逻辑正常
  2. 批量发起所有设备的影子请求,给Promise.all挂载了数据处理的回调,但没有用await等待这个Promise执行完成
  3. 同步返回初始化时的空数组devices_list,React拿到空数组触发第一次状态更新
  4. 后续影子请求陆续返回,往你之前返回的数组引用里push数据,此时页面会短暂渲染出部分已返回的设备
  5. 只要某一个影子请求失败,Promise.all直接抛出未捕获异常,整个状态更新流程中断,页面数据清空

这也是为什么你去掉影子请求逻辑、只返回设备列表时页面正常——那套逻辑是全程await等待结果返回后才return,没有时序问题,也不会因为子请求失败导致整体崩溃。

修复方案

  1. 去掉多余的手动Promise包装,给单个影子请求加错误兜底,避免单设备请求失败拖垮整个列表
  2. 用await等待Promise.all全部执行完成后,再返回组装好的完整数组,不要提前返回空数组引用
  3. 给外层调用加异常捕获,避免未捕获错误打断渲染
  4. 增加可选链判断,避免影子数据结构不完整时触发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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 01:57:11