React Query useMutation重复调用求助:MQTT触发API调用次数递增
问题原因分析
你的问题核心是MQTT事件监听重复绑定,导致每条消息触发多次API调用:
- 组件每次渲染时,顶层的
mqtt.connect会创建新的Client实例,useEffect依赖client变化,会重复执行并绑定新的connect/message监听 handleRfidCard函数每次渲染都会重新创建,导致useEffect依赖变化,进一步触发重复绑定- 旧的监听没有被清理,叠加后每条消息会触发所有已绑定的监听,API调用次数随之递增
解决方案
1. 用useRef保存MQTT Client实例
确保整个组件生命周期内只有一个Client,避免重复创建和连接:
import { useRef, useEffect, useCallback } from 'react'; import mqtt from 'mqtt'; // ...组件其他代码 const clientRef = useRef<mqtt.MqttClient | null>(null); useEffect(() => { // 仅初始化一次Client if (!clientRef.current) { clientRef.current = mqtt.connect(brokerUrl, { clientId, clean: true, username: import.meta.env.VITE_MQTT_BROKER_USERNAME, password: import.meta.env.VITE_MQTT_BROKER_PASSWORD, }); } const client = clientRef.current; // 单独定义事件处理函数,方便后续清理 const handleConnect = () => { client.subscribe("rfid", () => {}); }; const handleMessage = (topic: string, message: Buffer) => { if (topic === "rfid") { handleRfidCard(message.toString()); } }; // 绑定监听 client.on("connect", handleConnect); client.on("message", handleMessage); // 清理函数:移除监听,避免内存泄漏和重复触发 return () => { client.off("connect", handleConnect); client.off("message", handleMessage); // 组件卸载时可选断开连接 // client.end(); }; }, [handleRfidCard]); // 仅依赖稳定后的handleRfidCard
2. 用useCallback稳定handleRfidCard引用
避免函数每次渲染重新创建,导致useEffect重复执行:
const handleRfidCard = useCallback((rfidID: string) => { if (rfidID) { rfidCard.mutate(rfidID, { onSuccess: (data) => { capture(data.id, data.type); }, }); rfidHistory.mutate(rfidID); } }, [rfidCard, rfidHistory, capture]); // 依赖对应的mutation和capture函数
3. 额外检查:确保clientId稳定
如果clientId是动态生成的(比如每次渲染都生成新ID),会导致MQTT重复创建连接,需确保clientId在组件生命周期内唯一且稳定。
内容的提问来源于stack exchange,提问作者hathai
相关产品推荐
相关产品推荐

