React中SockJS主题订阅的位置及数据渲染问题
解决SockJS订阅数据渲染及Bootstrap表格更新问题
让我们一步步拆解并解决你的问题:
问题1:订阅逻辑与组件状态管理
你不需要把订阅逻辑移到其他函数,但核心是要把收到的消息存入组件的状态(state)——之前你只把消息打印到控制台,没有触发React的组件更新机制,所以数据无法渲染出来。
实现思路:
React组件只有在state或props变化时才会重新渲染,我们需要在收到SockJS消息时更新组件状态,让表格能实时响应数据变化。SockJsClient本身会在组件挂载时自动建立连接、订阅主题,放在render里完全没问题,不需要手动在其他生命周期函数处理(除非你需要更精细的连接控制)。
问题2:Bootstrap表格动态更新
结合状态管理,我们可以把收到的货币数据以parity为键存储在状态中,渲染表格时直接匹配对应行的数据,再加上开关控制是否接收更新。
完整实现代码(类组件版本):
import React, { Component } from 'react'; import SockJsClient from 'react-stomp'; class CurrencyTracker extends Component { constructor(props) { super(props); // 初始化状态:存储所有货币对数据,开关控制更新 this.state = { currencyData: { USDTRY: { buy: '', sell: '' }, EURTRY: { buy: '', sell: '' }, GBPTRY: { buy: '', sell: '' }, EURUSD: { buy: '', sell: '' } }, isTracking: true }; } // 处理收到的WebSocket消息 handleMessage = (msg) => { if (!this.state.isTracking) return; // 开关关闭时不更新数据 const { parity, buy, sell } = msg; this.setState(prevState => ({ currencyData: { ...prevState.currencyData, [parity]: { buy, sell } // 动态更新对应货币对的数据 } })); }; // 切换跟踪状态 toggleTracking = () => { this.setState(prevState => ({ isTracking: !prevState.isTracking })); }; render() { const { currencyData, isTracking } = this.state; return ( <div> {/* 跟踪开关 */} <div className="mb-3"> <label> <input type="checkbox" checked={isTracking} onChange={this.toggleTracking} /> {isTracking ? '🔄 正在跟踪实时数据' : '⏸️ 已暂停跟踪'} </label> </div> {/* SockJS客户端组件 */} <SockJsClient url='http://localhost:8080/websocket-example' topics={['/topic/currency']} onMessage={this.handleMessage} ref={(client) => {this.clientRef = client}} onDisconnect={() => console.log('WebSocket连接已断开')} /> {/* Bootstrap表格渲染 */} <div className="row"> <div className="col-md-12"> <table id="currencies" className="table table-hover"> <thead className="thead-dark"> <tr> <th>Currency Pair</th> <th>Buy</th> <th>Sell</th> </tr> </thead> <tbody> <tr> <td>USDTRY</td> <td>{currencyData.USDTRY.buy || '-'}</td> <td>{currencyData.USDTRY.sell || '-'}</td> </tr> <tr> <td>EURTRY</td> <td>{currencyData.EURTRY.buy || '-'}</td> <td>{currencyData.EURTRY.sell || '-'}</td> </tr> <tr> <td>GBPTRY</td> <td>{currencyData.GBPTRY.buy || '-'}</td> <td>{currencyData.GBPTRY.sell || '-'}</td> </tr> <tr> <td>EURUSD</td> <td>{currencyData.EURUSD.buy || '-'}</td> <td>{currencyData.EURUSD.sell || '-'}</td> </tr> </tbody> </table> </div> </div> </div> ); } } export default CurrencyTracker;
函数组件(React Hooks)版本:
如果你更习惯用函数组件,逻辑完全一致,只是用useState和useCallback替代类组件的状态和方法:
import React, { useState, useCallback } from 'react'; import SockJsClient from 'react-stomp'; const CurrencyTracker = () => { const [currencyData, setCurrencyData] = useState({ USDTRY: { buy: '', sell: '' }, EURTRY: { buy: '', sell: '' }, GBPTRY: { buy: '', sell: '' }, EURUSD: { buy: '', sell: '' } }); const [isTracking, setIsTracking] = useState(true); const handleMessage = useCallback((msg) => { if (!isTracking) return; const { parity, buy, sell } = msg; setCurrencyData(prev => ({ ...prev, [parity]: { buy, sell } })); }, [isTracking]); const toggleTracking = () => { setIsTracking(prev => !prev); }; return ( <div> {/* 跟踪开关 */} <div className="mb-3"> <label> <input type="checkbox" checked={isTracking} onChange={toggleTracking} /> {isTracking ? '🔄 正在跟踪实时数据' : '⏸️ 已暂停跟踪'} </label> </div> <SockJsClient url='http://localhost:8080/websocket-example' topics={['/topic/currency']} onMessage={handleMessage} ref={(client) => {window.clientRef = client}} /> {/* Bootstrap表格 */} <div className="row"> <div className="col-md-12"> <table id="currencies" className="table table-hover"> <thead className="thead-dark"> <tr> <th>Currency Pair</th> <th>Buy</th> <th>Sell</th> </tr> </thead> <tbody> <tr> <td>USDTRY</td> <td>{currencyData.USDTRY.buy || '-'}</td> <td>{currencyData.USDTRY.sell || '-'}</td> </tr> <tr> <td>EURTRY</td> <td>{currencyData.EURTRY.buy || '-'}</td> <td>{currencyData.EURTRY.sell || '-'}</td> </tr> <tr> <td>GBPTRY</td> <td>{currencyData.GBPTRY.buy || '-'}</td> <td>{currencyData.GBPTRY.sell || '-'}</td> </tr> <tr> <td>EURUSD</td> <td>{currencyData.EURUSD.buy || '-'}</td> <td>{currencyData.EURUSD.sell || '-'}</td> </tr> </tbody> </table> </div> </div> </div> ); }; export default CurrencyTracker;
额外优化提示:
- 数值格式化:可以用
toFixed(4)来保留4位小数,比如{currencyData.USDTRY.buy?.toFixed(4) || '-'},让数据更规整。 - 连接异常处理:利用
SockJsClient的onConnectFailure回调处理连接失败的情况,提升用户体验。
内容的提问来源于stack exchange,提问作者estherial
相关产品推荐
相关产品推荐

