You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中Stomp WebSocket事件监听无法获取最新状态的求助

问题描述

我有一个通过Stomp协议连接WebSocket的React组件,核心代码如下:

Stomp客户端连接代码

stompClient.current.connect(
    headers,
    () => {
        const url = `topic/url`;
        stompClient.current.subscribe(url, (payload) => {
            onEventReceived(payload);
        });
    },
    onError
);

onEventReceived处理函数代码

const onEventReceived = (payload) => {
    const newMessage = JSON.parse(payload.body);
    console.log('received message', newMessage);
    console.log('all messages', transcriptMessages);
    if (newMessage.isPartial) {
        if (!transcriptMessages.length) {
            setTranscriptMessages([newMessage]);
            return;
        }
        const messageIndex = transcriptMessages.findIndex((message) => message.uuid === newMessage.uuid);                
        transcriptMessages[messageIndex] = newMessage;
        setTranscriptMessages([...transcriptMessages]);
    }
    setTranscriptMessages([newMessage, ...transcriptMessages]);
};

遇到的问题:控制台输出的all messages始终是空数组,推测是React状态变更无法同步到WebSocket事件监听回调中,该怎么调整组件让状态变化能同步到回调里?


解决方案

问题根源是Stomp订阅回调捕获的是组件初始渲染时的状态闭包,后续状态更新后,回调里还是引用旧的状态值,所以打印出来一直是空数组。以下是两种可行的解决方式:

1. 使用状态更新函数(推荐)

React的setState支持传入函数,该函数会接收当前最新的状态作为参数,确保你拿到的是实时的状态值。修改后的onEventReceived代码如下:

const onEventReceived = (payload) => {
    const newMessage = JSON.parse(payload.body);
    console.log('received message', newMessage);
    
    setTranscriptMessages(prevMessages => {
        // prevMessages是当前最新的状态数组
        console.log('all messages', prevMessages);
        
        if (newMessage.isPartial) {
            if (!prevMessages.length) {
                return [newMessage];
            }
            // 创建数组副本,避免直接修改原状态
            const updatedMessages = [...prevMessages];
            const messageIndex = updatedMessages.findIndex(message => message.uuid === newMessage.uuid);
            // 增加判断,避免找不到对应uuid的情况
            if (messageIndex !== -1) {
                updatedMessages[messageIndex] = newMessage;
            }
            return updatedMessages;
        }
        // 非分段消息,添加到数组头部
        return [newMessage, ...prevMessages];
    });
};

2. 使用useRef同步最新状态

如果需要在回调中直接访问最新状态(而非仅用于更新),可以用useRef来同步状态的实时值:

首先在组件中定义ref并同步状态:

const transcriptMessagesRef = useRef([]);

// 每次状态更新时,同步ref的当前值
useEffect(() => {
    transcriptMessagesRef.current = transcriptMessages;
}, [transcriptMessages]);

然后修改onEventReceived函数,使用ref中的最新状态:

const onEventReceived = (payload) => {
    const newMessage = JSON.parse(payload.body);
    const currentMessages = transcriptMessagesRef.current;
    console.log('received message', newMessage);
    console.log('all messages', currentMessages);
    
    if (newMessage.isPartial) {
        if (!currentMessages.length) {
            setTranscriptMessages([newMessage]);
            return;
        }
        const updatedMessages = [...currentMessages];
        const messageIndex = updatedMessages.findIndex(message => message.uuid === newMessage.uuid);
        if (messageIndex !== -1) {
            updatedMessages[messageIndex] = newMessage;
        }
        setTranscriptMessages(updatedMessages);
    } else {
        setTranscriptMessages([newMessage, ...currentMessages]);
    }
};

额外注意事项

  • 禁止直接修改React状态数组(比如原代码中的transcriptMessages[messageIndex] = newMessage),必须创建新数组副本,否则React无法检测到状态变化,不会触发组件重渲染。
  • 第一种方法是React官方推荐的异步状态更新方案,逻辑更简洁,无需维护额外的ref变量,优先使用。

内容的提问来源于stack exchange,提问作者TheUnreal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 23:27:33