React useState钩子问题在MQTT通信中更新实时数据



故事

我用React Js和MQTT通信在地图上显示了很多实时位置数据。你可以把它想象成一个仪表盘,向所有优步司机显示实时位置。

我有7个设备将它们的数据广播到Rabbit MQ服务器。在Rabbit MQ中,我安装了MQTT插件,这样我就可以在React中使用MQTT从Rabbit MQ服务器检索数据。

来自每个设备的数据在随机时间广播。因此,一秒钟内可能没有数据,而一秒钟内某些设备会产生大量数据。

让我们假设这是一个从一个设备广播一次的示例数据:

{ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
or:
{ble.beacons: Array(0), channel.id: 10476, device.id: 3, device.name: "Device-3", device.type.id: 579, …}

目标我想做什么:

  1. 过滤每个项目(从设备广播):假设我有一个array来存储每个设备。因为我有7个设备,所以我将有一个长度为7的array
  • 如果array中没有设备id,则添加到array中。
  • 如果物品的设备id在array中找到,该物品将替换数组中的旧物品(具有相同的设备id)。
  1. 使用useState钩子更新arraydata(状态变量)

代码代码如下:

import React, { useEffect, useState } from 'react'
import mqtt from 'mqtt'
export default function RealtimeMarker() {
const [ data, setData ] = useState([])
let array = []
const usingMqtt = () => {
const url = 'ws://blahblahblah/ws'
const client = mqtt.connect(url)
const topicsToSubscribe = 'message/devices/+' // '+' is a wildcard

client.on('connect', () => {
console.log('connected')
client.subscribe(topicsToSubscribe)
})
client.on('message', (topic, message) => {
const itemMessage = JSON.parse(message.toString())
console.log('itemMessage: ', itemMessage)
// ADD NEW ITEM TO EMPTY DATA
if(data.length === 0) {
array.push(itemMessage)
}
// ADD NEW ITEM TO NON-EMPTY DATA
else {
for(let i = 0; i < data.length; i++) {
if(data[i]['device.id'] !== itemMessage['device.id'] && itemMessage['ble.beacons'] === null) {
array.push(itemMessage)
}
}
}

setData(array)
})
}
console.log('data: ', data.length, data)
useEffect(() => {
usingMqtt()
}, [])
return (
<div>
</div>
)
}
主题'message/devices/+'

中的+是所有主题的通配符。

依赖性:

"mqtt": "^4.2.8",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",

环境:

OS: Windows 10 Home
NPM: v6.14.8
Node: v12.9.0

问题:

data变量永远只更新两次。

10:29:46.179 RealtimeMarker.js:65 data:  0 []
10:29:46.326 RealtimeMarker.js:34 connected
10:29:46.610 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
10:29:46.611 RealtimeMarker.js:65 data:  1 [{…}]
10:29:48.845 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.046, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:29:48.846 RealtimeMarker.js:65 data:  2 (2) [{…}, {…}]
10:29:49.021 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.043, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:29:49.022 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.041, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:29:49.023 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.048, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:29:49.024 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.033, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:29:51.946 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.071, …}
10:29:53.236 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.006, …}
10:29:53.410 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.007, …}
10:29:53.410 RealtimeMarker.js:42 itemMessage:  {ble.beacons: Array(0), channel.id: 10476, device.id: 3, device.name: "Device-3", device.type.id: 579, …}
10:29:53.410 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.6, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:29:53.410 RealtimeMarker.js:42 itemMessage:  {ble.beacons: Array(0), channel.id: 10476, device.id: 3, device.name: "Device-3", device.type.id: 579, …}
10:29:53.411 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.6, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:29:56.570 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
10:29:58.468 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.048, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:29:58.637 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.041, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:30:01.984 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.067, …}
10:30:03.177 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:30:03.353 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.008, …}
10:30:03.354 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.608, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:03.354 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.512, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:03.354 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.512, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:06.771 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
10:30:11.039 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.05, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:30:11.238 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.037, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:30:11.415 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.735, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:11.416 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.735, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:11.417 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.746, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:11.418 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.785, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:11.585 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.754, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:11.585 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
10:30:11.586 RealtimeMarker.js:42 itemMessage:  {ble.beacons: Array(0), channel.id: 10476, device.id: 5, device.name: "Device-5", device.type.id: 579, …}
10:30:12.462 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.008, …}
10:30:12.636 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:30:12.636 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.512, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:12.636 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.558, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:12.637 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.549, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:16.475 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
10:30:21.963 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.067, …}
10:30:22.577 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.006, …}
10:30:22.749 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:30:22.750 RealtimeMarker.js:42 itemMessage:  {ble.beacons: Array(0), channel.id: 10476, device.id: 3, device.name: "Device-3", device.type.id: 579, …}
10:30:22.751 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.595, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:22.752 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.562, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:26.452 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
10:30:31.486 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.067, …}
10:30:32.226 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:30:32.401 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.006, …}
10:30:32.401 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.571, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:32.402 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.567, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:32.402 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.578, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:34.401 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.039, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:30:34.568 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.039, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
10:30:36.795 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
10:30:40.088 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.854, battery.charging.status: false, battery.current: 0, battery.voltage: 4.011, …}
10:30:40.248 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.553, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:40.248 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.556, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:40.248 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.553, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:40.248 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.043, ain.2: 2.553, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
10:30:41.425 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
10:30:41.599 RealtimeMarker.js:42 itemMessage:  {ble.beacons: Array(0), channel.id: 10476, device.id: 5, device.name: "Device-5", device.type.id: 579, …}
10:30:44.862 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.735, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:45.023 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.735, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:45.024 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.746, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:45.024 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.785, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:45.024 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.173, ain.2: 2.754, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
10:30:46.328 RealtimeMarker.js:42 itemMessage:  {ain.1: 0.087, ain.2: 3.234, battery.charging.status: false, battery.current: 0, battery.voltage: 4.066, …}
10:30:47.899 RealtimeMarker.js:34 connected

正如你所看到的,data只更新了两次,尽管所有7个设备的数据都被传输到React应用程序。

还有一件事不清楚。如您所见,在10:29:46.611处,数据的长度为1。如果我打开data,data的长度大于1,如下所示:

0: {ain.1: 0.173, ain.2: 2.974, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
1: {ain.1: 0.173, ain.2: 2.968, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
2: {ain.1: 0.173, ain.2: 2.972, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
3: {ain.1: 0.173, ain.2: 2.97, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
4: {ain.1: 0.173, ain.2: 2.955, battery.charging.status: false, battery.current: 0, battery.voltage: 4.004, …}
5: {ain.1: 0.087, ain.2: 3.033, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
6: {ain.1: 0.043, ain.2: 2.894, battery.charging.status: false, battery.current: 0, battery.voltage: 4.01, …}
7: {ain.1: 0.043, ain.2: 2.887, battery.charging.status: false, battery.current: 0, battery.voltage: 4.008, …}
8: {ain.1: 0.043, ain.2: 2.593, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}
9: {ain.1: 0.043, ain.2: 2.589, battery.charging.status: false, battery.current: 0, battery.voltage: 4.03, …}

问题
  1. 怎么会这样?我的代码有什么问题?
  2. 如何解决这个问题或实现目标?

注意

如果这种情况不是很清楚,请在评论区告诉我。我会尽快更新这个问题。

我认为您在关闭和状态变化方面有问题。

由于您只在挂载message事件时注册事件处理程序,因此array事件的事件处理程序将始终具有相同的引用。

这意味着每次接收到消息时,您都将推入相同的初始数组并将相同的引用存储到状态中。

由于引用没有改变,React将假定数组没有更新。

import React, { useEffect, useState } from 'react'
import mqtt from 'mqtt'
export default function RealtimeMarker() {
const [ data, setData ] = useState([])
console.log('data: ', data.length, data)
// Use useEffect to create client and event listener.
// No need to recreate usingMqtt function on every render.
useEffect(() => {
const url = 'ws://blahblahblah/ws'
const client = mqtt.connect(url)
const topicsToSubscribe = 'message/devices/+' // '+' is a wildcard

client.on('connect', () => {
console.log('connected')
client.subscribe(topicsToSubscribe);
})
client.on('message', (topic, message) => {
const itemMessage = JSON.parse(message.toString())
console.log('itemMessage: ', itemMessage)

// make use of alternate syntax of setState to ensure you are always using
// newest state values.
setData(currentData => {
// Create an array with a new reference.
// Without a new reference react assumes there is no change to the array.
let array = [...currentData]
if(currentData.length === 0) {
array.push(itemMessage)
}
else {
let found = 0
for(let i = 0; i < currentData.length; i++) {
console.log(currentData[i]['device.id'], itemMessage['device.id'], itemMessage['ble.beacons'])
if(currentData[i]['device.id'] === itemMessage['device.id']) {
found++
currentData[i] = itemMessage
}
}
if(found === 0) {
array.push(itemMessage)
}
}
return array
})
})
//Ensure client is closed on unmount of component.
return () => {
client.end();
}
}, []);
return (
<div>
</div>
)
}

相关内容

最新更新