我正在尝试使用钩子处理 React 中的对象列表。对象的更新是使用 MQTT 接收的。
我首先尝试使用一个名为mqtt-react-hooks的库(最近从Github中消失了(。该库提供了一个useSubscription
函数,该函数返回在订阅主题上收到的最新消息。
基本上我的组件看起来像这样,我的对象是节点:
function MQTTApp(props) {
const [nodes, setNodes] = useState([]);
const { lastMessageOnTopic } = useSubscription('node/#');
...
}
这种方法的问题在于,每次收到消息时都会呈现我的组件。当收到 MQTT 消息时,需要对其进行解析,并且并不总是导致节点更新。我想要的是,我的组件仅在节点列表有效更改时才呈现。
所以我尝试转储mqtt-react-hooks库并编写自己的代码。在它下面也使用 MQTT.js。它基于本文。
我的代码现在看起来像这样:
function MQTTApp(props) {
const [nodes, setNodes] = useState([]);
function handleMessage(m) {
...
setNodes([...nodes, newNode]);
}
useEffect(() => {
const client = mqttService.getClient();
mqttService.onMessage(client, handleMessage);
mqttService.subscribe(client, 'node/#');
return () => mqttService.closeConnection(client);
}, []);
...
}
这个想法是组件创建一个 MQTT 客户端并在挂载时订阅主题。我在这里遇到的问题是回调总是引用节点的初始列表(为空(。由于我将节点列表视为不可变,因此在调用setNodes
时总是创建一个副本,因此nodes
引用更改。所以最后,当收到更新时,我会继续丢失以前的节点。
我想不出一种干净简单的方法来解决这个问题。有人有想法吗?
谢谢
您的useEffect
执行一次。附加到onMessage
侦听器的函数引用handleMessage
nodes
始终使用节点的初始值(由于闭包(。
因此,请使用回调方法来设置状态。
function MQTTApp(props) {
const [nodes, setNodes] = useState([]);
function handleMessage(m) {
...
setNodes(prev => [...prev, newNode]); <-------- see here
}
useEffect(() => {
const client = mqttService.getClient();
mqttService.onMessage(client, handleMessage);
mqttService.subscribe(client, 'node/#');
return () => mqttService.closeConnection(client);
}, []);
...
}