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
相关产品推荐
相关产品推荐

