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

React应用中WebSocket发送JSON消息引发重复渲染问题求助

解决WebSocket提交后组件无限重渲染的问题

核心问题分析

你的代码存在两个关键问题,共同导致了循环重渲染:

  1. useWebSocket的配置对象每次组件渲染都会生成新的引用,触发hook重新初始化WebSocket连接;连接建立后收到消息更新lastJsonMessage,又会引发组件重渲染,最终形成循环。
  2. onSubmitClick的useCallback依赖项缺失sendJsonMessage,导致函数引用不稳定,既不符合React Hooks的依赖规则,也可能触发子组件不必要的重渲染。

具体修复步骤

1. 缓存WebSocket配置对象

用useMemo包裹useWebSocket的配置参数,确保每次渲染时配置对象的引用一致,避免hook重复初始化:

const wsOptions = useMemo(() => ({
  shouldReconnect: (closeEvent) => true,
  reconnectInterval: 100,
}), []);

const { sendJsonMessage, lastJsonMessage, readyState, getWebSocket } =
  useWebSocket("ws://localhost:8425/", wsOptions);

2. 补全useCallback的依赖项

将sendJsonMessage加入useCallback的依赖数组,保证函数引用稳定:

const onSubmitClick = useCallback(() => {
  sendJsonMessage({ subscribe: "DE000BASF111" });
}, [sendJsonMessage])

3. 正确处理WebSocket返回的消息

如果需要用lastJsonMessage更新ISINData,必须通过useEffect监听消息变化,避免在渲染阶段直接更新状态引发循环:

useEffect(() => {
  if (lastJsonMessage) {
    // 根据实际消息格式调整更新逻辑
    setISINData(prev => [...prev, lastJsonMessage]);
  }
}, [lastJsonMessage]);

修复后的完整代码片段

const [ISINData, setISINData] = useState<ISINDataType[]>([]);

const wsOptions = useMemo(() => ({
  shouldReconnect: (closeEvent) => true,
  reconnectInterval: 100,
}), []);

const { sendJsonMessage, lastJsonMessage, readyState, getWebSocket } =
  useWebSocket("ws://localhost:8425/", wsOptions);

const onSubmitClick = useCallback(() => {
  sendJsonMessage({ subscribe: "DE000BASF111" });
}, [sendJsonMessage])

// 处理WebSocket返回的消息
useEffect(() => {
  if (lastJsonMessage) {
    // 按实际业务逻辑更新ISINData
    setISINData(prevData => [...prevData, lastJsonMessage]);
  }
}, [lastJsonMessage]);

return (
  <div className="App h-full container">
    <span>The WebSocket is currently {connectionStatus}</span>
    <div className="flex w-full h-full flex-col justify-center">
      <div className="flex items-center p-4 box-border-sizing justify-center">
        <ISINForm onSubmit={onSubmitClick} className="flex items-center" />
      </div>
      <Card
        classNames={classNameCreator([
          "flex-grow-1 pr-4 pl-4 box-border-sizing",
          styles.content,
        ])}
      >
        <ul className={classNameCreator([styles["watch-list"], "p-0 m-0"])}>
          {ISINData?.map((ISIN) => (
            <ISINCard
              ISINData={ISIN}
              key={ISIN?.isin}
              onClick={() => onRowClick(ISIN?.isin)}
            />
          ))}
        </ul>
      </Card>
    </div>
  </div>
);

额外优化建议

  • 给ISINForm组件加上React.memo包裹,避免因父组件传递的onSubmit函数引用变化而触发不必要的重渲染。
  • 如果connectionStatus是基于readyState计算的,也用useMemo缓存计算结果,进一步稳定渲染逻辑。

内容的提问来源于stack exchange,提问作者N.SH

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:02:45