故事
我用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, …}
目标我想做什么:
- 过滤每个项目(从设备广播):假设我有一个
array
来存储每个设备。因为我有7个设备,所以我将有一个长度为7的array
。
- 如果
array
中没有设备id,则添加到array
中。 - 如果物品的设备id在
array
中找到,该物品将替换数组中的旧物品(具有相同的设备id)。
- 使用
useState
钩子更新array
和data
(状态变量)
代码代码如下:
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, …}
问题- 怎么会这样?我的代码有什么问题?
- 如何解决这个问题或实现目标?
注意
如果这种情况不是很清楚,请在评论区告诉我。我会尽快更新这个问题。
我认为您在关闭和状态变化方面有问题。
由于您只在挂载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>
)
}