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

React应用多标签页打开时Event Source引发数据重复问题排查

问题分析与解决方案

看起来你的问题核心在于新标签页打开时,原标签页的Event Source连接收到了重复数据,导致表格数据重复。虽然每个标签页是独立的React实例,各自建立了独立的SSE连接,但问题大概率出在后端的SSE推送逻辑上,结合你的前端代码,我们来一步步拆解:

可能的原因

1. 后端采用了广播式推送

如果你的Spring Boot后端在处理SSE连接时,是将数据广播给所有已连接的客户端(而不是只发送给刚建立连接的新客户端),那么当你打开新标签页建立新连接时,后端会把全量的shifts数据推送给所有在线的连接,包括原标签页的连接。这就会导致原标签页的onmessage再次触发,把所有数据追加到已有数组中,造成重复。

比如很多新手在实现Spring Boot SSE时,会用一个全局的List<SseEmitter>来存储所有连接,当有新连接加入时,遍历这个列表给所有Emitter发送数据,这就会触发广播行为。

2. 前端状态更新逻辑的追加特性

你的前端代码中,setShiftArray是用[...oldArray, JSON.parse(event.data)]的方式追加数据,这种逻辑只有在后端推送增量数据(比如新增的单个shift)时才合理。如果后端推送的是全量数据,这种追加方式必然会导致重复。

解决方案

第一步:修复后端的SSE推送逻辑

确保后端在新客户端建立连接时,只向当前新连接发送全量数据,而不是广播给所有客户端。

举个Spring Boot的正确示例(假设用SseEmitter):

@GetMapping("/shifts/getAllShifts")
public SseEmitter getAllShifts(HttpServletRequest request) {
    SseEmitter emitter = new SseEmitter();
    // 只向当前emitter发送全量数据
    List<Shift> shifts = shiftService.getAllShifts();
    try {
        emitter.send(SseEmitter.event().data(shifts));
        // 如果需要后续推送增量,可以在这里维护emitter到集合,但注意只推送增量给所有客户端,而不是全量
    } catch (IOException e) {
        emitter.completeWithError(e);
    }
    // 可以将emitter加入全局集合,用于后续增量推送,但不要在新连接时广播全量
    return emitter;
}

如果你的需求是后续有数据更新时,广播增量给所有客户端,那没问题,但新连接建立时只发送全量给当前客户端。

第二步:优化前端状态更新逻辑

根据后端推送的数据类型调整:

  • 如果后端推送的是全量数据:直接替换数组,而不是追加
    eventSource.onmessage = (event: any) => {
        // 直接用新的全量数据替换旧数组
        setShiftArray(JSON.parse(event.data));
    };
    
  • 如果后端推送的是增量数据(单个shift):添加去重逻辑,比如根据shift的唯一ID过滤
    eventSource.onmessage = (event: any) => {
        const newShift = JSON.parse(event.data);
        setShiftArray((oldArray: any) => {
            // 检查是否已存在相同ID的shift,不存在才添加
            if (!oldArray.some(shift => shift.id === newShift.id)) {
                return [...oldArray, newShift];
            }
            return oldArray;
        });
    };
    

额外检查:确保Event Source连接正确关闭

你的useEffect返回了关闭连接的函数,这部分是对的,确保组件卸载时关闭连接,避免无效连接占用资源。

总结

最可能的根源是后端的广播式推送导致原标签页重复接收全量数据,先排查后端的SSE实现,再根据后端推送的数据类型调整前端的状态更新逻辑,就能解决数据重复的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 15:03:15