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

React中WebSocket获取的日志列表无法即时渲染的解决方法

问题解决方案

1. 修复useReducer的状态更新逻辑

你的核心问题是直接修改了原状态数组,导致React无法检测到状态变化。React依赖状态的引用变更触发组件重渲染,直接对prev数组执行push操作属于原地修改,状态引用未改变,因此组件不会更新视图。

修改reducer函数,返回新数组替代原地修改:

const [logs, pushLogs] = useReducer(
  (prev, next) => [...prev, ...next], // 用扩展运算符创建新数组,避免原地修改
  ["Initializing..."]
);

2. 修正WebSocket事件处理逻辑

你在message事件中返回清理函数的写法无效,useSWRSubscription的回调需直接返回全局清理逻辑,事件内部返回的函数不会被执行。收到"Finished"标识时直接关闭socket即可:

useSWRSubscription(
  `ws://${host}/api/users/logs?id=${props.id}`,
  (key, { next }) => {
    const socket = new WebSocket(key);
    
    socket.addEventListener("message", ({ data }) => {
      pushLogs(data.split("\n"));

      // 收到结束标识时直接关闭socket
      if (data.includes("Finished")) {
        socket.close();
      }
    });

    socket.addEventListener("error", (event) => next(event.error));
    
    // 组件卸载/key变化时执行的全局清理函数
    return () => socket.close();
  }
);

3. 可选渲染优化

当前日志会连在一起显示,建议添加换行符;同时尽量避免用index作为key(日志内容唯一时优先用内容当key):

{logs.map((log, index) => (
  <span key={log || index}> {/* 优先用日志内容作为key,空内容时回退到index */}
    {log}
    <br />
  </span>
))}

问题根源总结

  • React状态遵循不可变原则,必须通过返回新对象/数组触发重渲染,原地修改原状态无法被React检测到。
  • useSWRSubscription的回调返回的清理函数是全局资源清理逻辑,事件内部返回的函数不会被执行,导致之前的socket关闭逻辑未生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:37:34