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

React中Hermes引擎报不可变对象赋值错误求助

问题:React Native中AWS IoT MQTT连接触发不可变对象修改错误

未尝试修改任何不可变值,但页面加载时反复出现错误:Error: You attempted to set the key '_i' with the value '1' on an object that is meant to be immutable and has been frozen., js engine: hermes

连接已成功建立,但单独运行页面代码时无错误,使用应用的Stack Navigator导航时则会出现该错误。以下是使用AWSIoTData建立MQTT连接的useEffect代码:

useEffect(() => {
    let dataPayload
    const clients = AWSIoTData.device({
      clientId: '',
      protocol: 'wss',
      accessKeyId: accessKeyId,
      secretKey: secretKey,
      keyPath: privatePathIs,
      certPath: certificatePathIs,
      caPath: caPathIs,
      host: host,
      port: 443,
      debug: true
    });


    clients.on('connect', function () {
      console.log('Connected');
      clients.subscribe(topic);
    });
    clients.on('reconnect', function () {
      console.log('reconnects');
      // clients.subscribe('example-topic');
    });

    clients.on('error', function (err) {
      console.log('Error', err);
    });

    clients.on('message', async function (topic, payload) {
      var parsedData = JSON.parse(payload.toString());
      // let dataConvert = bin2String(payload)
      dataPayload = await VecMqttPayloadBeautify(topic, parsedData);

      dispatch({
        type: actionTypes.SET_ALLDATA_PAYLOAD,
        payload: dataPayload,
      });
      // console.log('inner message', parsedData);
      // console.log('inner payload', dataPayload);
    });

  }, [])

原因分析与解决办法

核心原因

  1. 未清理MQTT客户端实例:Stack Navigator默认会保留栈中之前的页面组件实例,你的useEffect没有清理逻辑,导致多个MQTT客户端同时运行,客户端内部的重试或状态更新逻辑可能修改了被React冻结的对象(比如Redux状态或组件内部不可变状态)。
  2. 空clientId导致连接冲突:AWS IoT要求每个连接的clientId唯一,空字符串会导致重复连接,客户端的重试机制触发内部对象修改,进而触发冻结对象错误。
  3. 异步dispatch的不安全操作:message回调中的异步函数完成后,组件可能已经被卸载或状态对象已被冻结,此时dispatch可能意外修改了不可变对象。

解决步骤

1. 添加组件卸载时的清理逻辑

在useEffect中返回清理函数,断开MQTT连接并移除所有监听,避免残留实例干扰:

useEffect(() => {
    let dataPayload
    // 生成唯一clientId,避免重复连接
    const clientId = `mqtt-client-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
    const clients = AWSIoTData.device({
      clientId: clientId,
      protocol: 'wss',
      accessKeyId: accessKeyId,
      secretKey: secretKey,
      keyPath: privatePathIs,
      certPath: certificatePathIs,
      caPath: caPathIs,
      host: host,
      port: 443,
      debug: true
    });

    // 原有的回调逻辑保持不变
    clients.on('connect', function () {
      console.log('Connected');
      clients.subscribe(topic);
    });
    clients.on('reconnect', function () {
      console.log('reconnects');
    });
    clients.on('error', function (err) {
      console.log('Error', err);
    });
    clients.on('message', async function (topic, payload) {
      var parsedData = JSON.parse(payload.toString());
      dataPayload = await VecMqttPayloadBeautify(topic, parsedData);

      dispatch({
        type: actionTypes.SET_ALLDATA_PAYLOAD,
        payload: dataPayload,
      });
    });

    // 清理函数:组件卸载时断开连接
    return () => {
      if (clients) {
        clients.end(); // 关闭MQTT连接
        clients.removeAllListeners(); // 移除所有事件监听
      }
    };
  }, [accessKeyId, secretKey, privatePathIs, certificatePathIs, caPathIs, host, topic, dispatch])

注意:必须把useEffect依赖数组中用到的所有外部变量(如accessKeyId、topic、dispatch)都加进去,避免闭包导致的旧值引用问题。

2. 确保clientId唯一

绝对不能使用空字符串作为clientId,用时间戳+随机字符串生成唯一标识,避免AWS IoT端的连接冲突。

3. 安全处理异步dispatch

在dispatch前检查组件是否仍处于挂载状态,避免对已卸载组件的状态进行操作:

useEffect(() => {
    let isMounted = true; // 标记组件是否挂载
    const clientId = `mqtt-client-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
    const clients = AWSIoTData.device({ /* 配置不变 */ });

    clients.on('message', async function (topic, payload) {
      var parsedData = JSON.parse(payload.toString());
      dataPayload = await VecMqttPayloadBeautify(topic, parsedData);
      
      // 仅在组件挂载时执行dispatch
      if (isMounted) {
        dispatch({
          type: actionTypes.SET_ALLDATA_PAYLOAD,
          payload: dataPayload,
        });
      }
    });

    return () => {
      isMounted = false; // 组件卸载时标记为未挂载
      clients.end();
      clients.removeAllListeners();
    };
  }, [/* 依赖项 */])

内容的提问来源于stack exchange,提问作者Arpit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 07:17:54