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

React使用useState更新MQTT实时设备数据异常问题咨询

问题原因

  1. 闭包陷阱导致读取旧状态:useEffect依赖为空数组,仅在组件首次挂载时执行一次,内部绑定的MQTT消息回调始终引用首次渲染时的data状态(初始空数组),后续状态更新后回调内无法拿到最新的data值,所有逻辑判断都基于旧值运行。
  2. 消息处理逻辑错误:
    • 原有遍历逻辑为只要现有数组中存在任意一条数据ID和新消息ID不匹配就插入新消息,会导致同ID消息被重复插入
    • 额外增加的itemMessage['ble.beacons'] === null判断不符合给出的上报数据格式,会过滤掉大部分合法上报数据
  3. 数组引用异常:组件顶层声明的array变量被首次渲染的闭包持续持有,所有新消息都往同一个数组对象中push。后续调用setData时传入的都是同一个数组引用,React判定状态没有变更就不会触发重渲染,因此data仅在前两次有引用变更时触发更新。控制台打印的是数组的引用,展开后显示的是实时的最新内容,和打印时的长度快照不符,就出现了你看到的日志异常。

修复方案

使用useState的函数式更新语法规避闭包问题,修改消息处理逻辑匹配业务需求,同时补充MQTT连接的卸载清理逻辑避免内存泄漏,修复后代码如下:

import React, { useEffect, useState } from 'react'
import mqtt from 'mqtt'

export default function RealtimeMarker() {
    const [data, setData] = useState([])

    useEffect(() => {
        const url = 'ws://blahblahblah/ws'
        const client = mqtt.connect(url)
        const topicsToSubscribe = 'message/devices/+' 

        client.on('connect', () => {
            console.log('connected')
            client.subscribe(topicsToSubscribe)
        })

        client.on('message', (topic, message) => {
            const itemMessage = JSON.parse(message.toString())
            console.log('itemMessage: ', itemMessage)
            // 函数式更新直接拿到最新的prev状态,规避闭包问题
            setData(prev => {
                // 查找是否存在同ID设备
                const existIndex = prev.findIndex(item => item['device.id'] === itemMessage['device.id'])
                if (existIndex > -1) {
                    // 存在则替换对应位置的数据,返回新数组
                    const newData = [...prev]
                    newData[existIndex] = itemMessage
                    return newData
                } else {
                    // 不存在则追加新数据,最多保留7条,可根据实际需求调整限制
                    return prev.length < 7 ? [...prev, itemMessage] : prev
                }
            })
        })

        // 组件卸载时清理MQTT连接,避免内存泄漏
        return () => {
            client.unsubscribe(topicsToSubscribe)
            client.end()
        }
    }, [])

    console.log('data: ', data.length, data)

    return (
        <div>
        </div>
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 12:21:02