React+Redux集成MQTT:单次连接与登出断开问题排查
问题修复:React集成MQTT实现登录连接、登出断开
核心问题分析
- 自动重复重连:模块加载时全局执行
mqtt.connect(),搭配配置reconnectPeriod:1000,导致连接异常或断开后每秒自动重试,connectedAt持续变化。 - 无效的客户端存储:尝试将MQTT客户端实例存入
localStorage,但实例无法被JSON序列化,会丢失核心方法,完全没必要。 - 断开连接不彻底:调用
mqttClient.end()时未禁止重连,断开后客户端仍会自动发起连接请求。
修复方案与代码修改
1. 调整MQTT客户端初始化逻辑
不在模块全局创建客户端,而是在mqttConnect动作中按需创建,确保只有登录时才发起连接。
2. 修正断开连接逻辑
调用end(true)强制禁止重连,避免断开后自动重试。
3. 移除无效的localStorage存储
客户端实例无需存入本地,直接通过Redux状态管理即可。
4. 优化Reducer状态定义
统一连接状态的语义,避免状态混淆。
修改后的mqttActions.js
import { CONNECT_MQTT_FAILURE, CONNECT_MQTT_REQUEST, CONNECT_MQTT_SUCCESS, DISCONNECT_MQTT_FAILURE, DISCONNECT_MQTT_REQUEST, DISCONNECT_MQTT_SUCCESS } from "../constants/mqttConstants" import mqtt from 'mqtt' const mqttHost = "host ip address here"; const mqttPort = 8083; const mqttUrl = `ws://${mqttHost}:${mqttPort}/mqtt` const mqttOptions = { keepalive: 30, protocolId: 'MQTT', protocolVersion: 4, clean: true, reconnectPeriod: 1000, connectTimeout: 30 * 1000, clientId: "bharath", will: { topic: 'WillMsg', payload: 'Connection Closed abnormally..!', qos: 0, retain: false }, rejectUnauthorized: false }; // 全局存储客户端实例,避免重复创建 let mqttClient = null; export const mqttConnect = () => async (dispatch) => { try { dispatch({ type: CONNECT_MQTT_REQUEST }) // 仅当客户端未创建时才初始化连接 if (!mqttClient) { mqttClient = mqtt.connect(mqttUrl, mqttOptions); // 监听连接成功事件,确保连接真正建立后再分发成功状态 mqttClient.on('connect', () => { dispatch({ type: CONNECT_MQTT_SUCCESS, payload: mqttClient }) }); // 监听连接错误,分发失败状态 mqttClient.on('error', (err) => { dispatch({ type: CONNECT_MQTT_FAILURE, payload: err.message }) }); } else if (mqttClient.connected) { // 若已连接,直接分发成功状态 dispatch({ type: CONNECT_MQTT_SUCCESS, payload: mqttClient }) } } catch (error) { dispatch({ type: CONNECT_MQTT_FAILURE, payload: error.response && error.response.data.message ? error.response.data.message : error.message }) } } export const mqttDisconnect = () => (dispatch) => { try { dispatch({ type: DISCONNECT_MQTT_REQUEST }) if (mqttClient) { // end(true) 强制关闭连接并禁止自动重连 mqttClient.end(true); // 重置客户端实例,确保下次登录重新创建 mqttClient = null; } dispatch({ type: DISCONNECT_MQTT_SUCCESS }) } catch (error) { dispatch({ type: DISCONNECT_MQTT_FAILURE, payload: error.response && error.response.data.message ? error.response.data.message : error.message }) } }
修改后的Reducer代码
import { CONNECT_MQTT_FAILURE, CONNECT_MQTT_REQUEST, CONNECT_MQTT_SUCCESS, DISCONNECT_MQTT_FAILURE, DISCONNECT_MQTT_REQUEST, DISCONNECT_MQTT_SUCCESS } from "../constants/mqttConstants" export const connectMqttReducer = (state = { status: 'disconnected' }, action) => { switch (action.type) { case CONNECT_MQTT_REQUEST: return { ...state, status: 'connecting', error: null } case CONNECT_MQTT_SUCCESS: return { status: 'connected', client: action.payload, error: null } case CONNECT_MQTT_FAILURE: return { status: 'disconnected', error: action.payload } default: return state } } export const disconnectMqttReducer = (state = {}, action) => { switch (action.type) { case DISCONNECT_MQTT_REQUEST: return { status: 'disconnecting' } case DISCONNECT_MQTT_SUCCESS: return { status: 'disconnected' } case DISCONNECT_MQTT_FAILURE: return { status: 'connected', error: action.payload } default: return state } }
关键说明
- 按需创建客户端:仅在登录触发
mqttConnect时创建客户端,避免模块加载时自动连接。 - 监听连接事件:通过
mqttClient.on('connect')确保连接真正建立后再更新Redux状态,避免状态与实际连接情况不符。 - 彻底断开连接:
end(true)参数会禁止客户端自动重连,同时重置mqttClient实例,确保下次登录重新初始化。 - 移除localStorage存储:MQTT客户端实例无法被序列化存储,直接通过Redux管理状态即可。
内容的提问来源于stack exchange,提问作者surya bharath
相关产品推荐
相关产品推荐

