使用React钩子和MQTT处理对象列表

时间:2020-05-22 22:27:42

标签: reactjs react-hooks mqtt immutability

我正在尝试使用挂钩处理React中的对象列表。使用MQTT接收对象的更新。

我首先尝试使用一个名为mqtt-react-hooks的库(该资源最近从Github中消失了)。该库提供了useSubscription函数,该函数除其他功能外还返回在订阅的主题上收到的最新消息。

基本上我的组件看起来像这样,我的对象是节点:

function MQTTApp(props) {
   const [nodes, setNodes] = useState([]);
   const { lastMessageOnTopic } = useSubscription('node/#');
   ...
}

此方法的问题在于,每次收到消息时都会呈现我的组件。收到MQTT消息后,需要对其进行解析,并且并不总是导致进行节点更新。我想当节点列表有效更改时,仅仅渲染我的组件。

因此,我尝试转储mqtt-react-hooks库并编写自己的代码。在其下方还使用MQTT.js。它基于this article

我的代码现在看起来像这样:

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 引用更改。因此,最后,当收到更新时,我会不断丢失先前的节点。

我想不出一种干净,简单的方法来处理这个问题。有人有主意吗?

谢谢

1 个答案:

答案 0 :(得分:1)

您的useEffect被执行一次。 nodes函数引用中的handleMessage(附加到onMessage侦听器)始终使用节点的初始值(由于闭包)。

因此,请使用回调方法来设置状态。

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);
  }, []);
  ...
}