mqtt-react-hooks 订阅者在一条消息后停止工作
mqtt-react-hooks Subscriber stops working after one message
我有一个使用 mqtt-react-hooks 和 redux 的简单 React 应用程序。每次订阅者收到新消息时,我都想更新我的 redux 存储。
Subscriber.tsx
import React, { useEffect} from 'react';
import { useSubscription } from 'mqtt-react-hooks';
import { useAppDispatch } from '../features/item/hooks';
import { addItem } from '../features/item/item-slice';
const Subscriber = () => {
const { message } = useSubscription('queue');
const dispatch = useAppDispatch();
useEffect(() => {
if (message && message.message) {
dispatch(addItem(JSON.parse(message.message)));
}
}, [message]);
return (
<span>{message}</span>
);
};
export default Subscriber
App.tsx
import React from 'react';
import './App.css';
import {useAppSelector} from './features/item/hooks'
import { Connector } from 'mqtt-react-hooks'
import Subscriber from './mqtt/Subscriber'
function App() {
const items = useAppSelector((state) => state.item.items);
return (
<>
<Connector brokerUrl="ws://localhost:9001"
options={{keepalive: 10}}>
<div className="item-holder">
{Array.from(items, ([key, it]) => ({ key, it })).map( (kvp) => { return <div>{kvp.it} key={kvp.key}></div>})}
</div>
<Subscriber />
</Connector>
</>
);
}
export default App;
如果我从订阅者中删除 useEffect
,就会收到并更新消息。我可以发送任意数量的消息。但是,当我在 useEffect
中调用 dispatch(addItem(...
时,它会收到第一条消息,但会忽略所有以后的消息。我的 mosquitto 代理说客户端已关闭连接。它从不尝试重新连接。
我对反应很陌生。我有一种感觉,我根本没有做对。我真正想要的是一个 redux 存储,它根据来自 mqtt 主题的消息维护状态。该应用程序具有允许用户将消息发布回 mqtt 代理并更改 redux 状态的按钮。
编辑
根据要求,这是 addItem 代码。
import {createSlice, PayloadAction} from '@reduxjs/toolkit'
interface ItemState {
items: Item[],
}
const initialState: ItemState = {
items: []
}
const orderSlice = createSlice({
name: 'items',
initialState,
reducers: {
addItem(state, action: PayloadAction<Item>) {
state.items.push(action.payload);
return state;
}
}
});
export const { addItem } = itemSlice.actions;
export default itemSlice.reducer;
而 useAppDispatch 来自 ./features/item/hooks
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { RootState, AppDispatch } from './item-store'
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
但是,我要补充一点,我摆脱了这个并使用了通常的 useDispatch 和 useSelector 而不是“useApp____”版本并得到了相同的结果。
我认为问题出在 mqtt-react-hooks
钩子上,但我的反应能力还不够高,无法解决。
似乎发生了一系列事情导致 Connector
重新呈现并断开连接,这是我认为正在发生的事情:
App
正在订阅存储状态,导致它在每次收到新消息时重新呈现。
- 每次
App
呈现时,您都在重新创建 mqtt 配置对象,因为您传递的是对象文字 {keepalive: 10}
- 在Connector.tsx第48行,
mqttConnect
回调依赖于mqtt选项对象。 React 进行引用相等性检查,发现选项已更改,并导致重新创建回调。
- 在 Connector.tsx 第 59 行,这导致 useEffect 重新运行,因为回调发生了变化,它调用了它的 teardown 函数,从而结束了 mqtt 连接。
要修复它,您应该在 App
之外创建 MQTT 选项,这样它们就不会改变。
我有一个使用 mqtt-react-hooks 和 redux 的简单 React 应用程序。每次订阅者收到新消息时,我都想更新我的 redux 存储。
Subscriber.tsx
import React, { useEffect} from 'react';
import { useSubscription } from 'mqtt-react-hooks';
import { useAppDispatch } from '../features/item/hooks';
import { addItem } from '../features/item/item-slice';
const Subscriber = () => {
const { message } = useSubscription('queue');
const dispatch = useAppDispatch();
useEffect(() => {
if (message && message.message) {
dispatch(addItem(JSON.parse(message.message)));
}
}, [message]);
return (
<span>{message}</span>
);
};
export default Subscriber
App.tsx
import React from 'react';
import './App.css';
import {useAppSelector} from './features/item/hooks'
import { Connector } from 'mqtt-react-hooks'
import Subscriber from './mqtt/Subscriber'
function App() {
const items = useAppSelector((state) => state.item.items);
return (
<>
<Connector brokerUrl="ws://localhost:9001"
options={{keepalive: 10}}>
<div className="item-holder">
{Array.from(items, ([key, it]) => ({ key, it })).map( (kvp) => { return <div>{kvp.it} key={kvp.key}></div>})}
</div>
<Subscriber />
</Connector>
</>
);
}
export default App;
如果我从订阅者中删除 useEffect
,就会收到并更新消息。我可以发送任意数量的消息。但是,当我在 useEffect
中调用 dispatch(addItem(...
时,它会收到第一条消息,但会忽略所有以后的消息。我的 mosquitto 代理说客户端已关闭连接。它从不尝试重新连接。
我对反应很陌生。我有一种感觉,我根本没有做对。我真正想要的是一个 redux 存储,它根据来自 mqtt 主题的消息维护状态。该应用程序具有允许用户将消息发布回 mqtt 代理并更改 redux 状态的按钮。
编辑
根据要求,这是 addItem 代码。
import {createSlice, PayloadAction} from '@reduxjs/toolkit'
interface ItemState {
items: Item[],
}
const initialState: ItemState = {
items: []
}
const orderSlice = createSlice({
name: 'items',
initialState,
reducers: {
addItem(state, action: PayloadAction<Item>) {
state.items.push(action.payload);
return state;
}
}
});
export const { addItem } = itemSlice.actions;
export default itemSlice.reducer;
而 useAppDispatch 来自 ./features/item/hooks
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { RootState, AppDispatch } from './item-store'
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
但是,我要补充一点,我摆脱了这个并使用了通常的 useDispatch 和 useSelector 而不是“useApp____”版本并得到了相同的结果。
我认为问题出在 mqtt-react-hooks
钩子上,但我的反应能力还不够高,无法解决。
似乎发生了一系列事情导致 Connector
重新呈现并断开连接,这是我认为正在发生的事情:
App
正在订阅存储状态,导致它在每次收到新消息时重新呈现。- 每次
App
呈现时,您都在重新创建 mqtt 配置对象,因为您传递的是对象文字{keepalive: 10}
- 在Connector.tsx第48行,
mqttConnect
回调依赖于mqtt选项对象。 React 进行引用相等性检查,发现选项已更改,并导致重新创建回调。 - 在 Connector.tsx 第 59 行,这导致 useEffect 重新运行,因为回调发生了变化,它调用了它的 teardown 函数,从而结束了 mqtt 连接。
要修复它,您应该在 App
之外创建 MQTT 选项,这样它们就不会改变。