如何使用Highcharts React库动态更新市场深度图表数据?
问题:Highcharts React 市场深度图表无法实时更新数据
我已成功使用Highcharts React组件将表格中的数据绘制为市场深度图表,但存储买盘(bids)和卖盘(asks)数据的数组会持续更新,当前图表仅能通过刷新页面同步数据。
现有代码
class MarketDepth extends React.Component<Props, State> { ... chart = null; state = { selectedBid: null, selectedAsk: null, }; chartOptions = { chart: { type: 'area', zoomType: 'xy', }, title: { text: 'Market Depth Chart', style: { color: '#FFFFFF', fontSize: '20px', lineHeight: '120%', fontWeight: '600', }, }, xAxis: { minPadding: 0, maxPadding: 0, crosshair: true, lineWidth: 0, gridLineWidth: 0, tickLength: 4, plotLines: [ { color: '#FFFFFF', width: 1, value: this.getAverageLine(), // 设置实际价格线数值 label: { text: 'Actual price', rotation: 90, align: 'right', style: { fonstStyle: 'italic', // 存在拼写错误 }, }, }, ], title: { text: 'Price', }, }, yAxis: [ { crosshair: true, lineWidth: 0, gridLineWidth: 0, title: { text: 'Acc', }, tickWidth: 1, tickLength: 5, tickPosition: 'inside', labels: { align: 'left', x: 8, }, }, { opposite: true, linkedTo: 0, lineWidth: 0, gridLineWidth: 0, title: { text: 'Acc', }, tickWidth: 1, tickLength: 5, tickPosition: 'inside', labels: { align: 'right', x: -8, }, }, ], legend: { enabled: false, }, plotOptions: { area: { states: { hover: { enabled: false, lineWidthPlus: 0, }, inactive: { opacity: 1, }, }, marker: { enabled: false }, fillOpacity: 0.2, lineWidth: 1, step: 'center', }, }, tooltip: { headerFormat: '<span style="font-size=10px;">Price: {point.key}</span><br/>', valueDecimals: 2, }, series: [ { name: 'Bids', data: this.getBidOrders(), step: 'left', }, { name: 'Asks', data: this.getAskOrders(), color: '#fc5857', step: 'right', }, ], }; getBidOrders() { ... } getAskOrders() { ... } ... render() { return ( <div id='chartContainer'> <HighchartsReact highcharts={Highcharts} options={this.chartOptions} allowChartUpdate /> </div> ) } }
数据格式示例
getAskOrders()和getBidOrders()返回的二维数组格式:
[ [2179.25, 30], [2179, 70], [2178.75, 113], [2178.5, 159], [2178.25, 206] ]
已尝试方案
- 使用React useState钩子管理chartOptions的状态
- 尝试利用chartOptions中的events属性更新图表值
解决方案
方法1:通过React状态管理动态更新配置
将chartOptions放入组件状态,当数据更新时重新生成配置并更新状态,触发组件重渲染,Highcharts React会自动同步图表:
class MarketDepth extends React.Component<Props, State> { chart = null; state = { selectedBid: null, selectedAsk: null, chartOptions: {} // 初始化空配置 }; componentDidMount() { // 挂载时初始化图表配置 this.setState({ chartOptions: this.getChartOptions() }); // 这里可以添加数据更新监听(如WebSocket) // this.setupDataListener(); } componentDidUpdate(prevProps) { // 当props中的买卖盘数据变化时,更新图表配置 if (prevProps.bids !== this.props.bids || prevProps.asks !== this.props.asks) { this.setState({ chartOptions: this.getChartOptions() }); } } getChartOptions() { return { chart: { type: 'area', zoomType: 'xy', }, title: { text: 'Market Depth Chart', style: { color: '#FFFFFF', fontSize: '20px', lineHeight: '120%', fontWeight: '600', }, }, xAxis: { minPadding: 0, maxPadding: 0, crosshair: true, lineWidth: 0, gridLineWidth: 0, tickLength: 4, plotLines: [ { color: '#FFFFFF', width: 1, value: this.getAverageLine(), label: { text: 'Actual price', rotation: 90, align: 'right', style: { fontStyle: 'italic', // 修正拼写错误 }, }, }, ], title: { text: 'Price', }, }, yAxis: [ { crosshair: true, lineWidth: 0, gridLineWidth: 0, title: { text: 'Acc', }, tickWidth: 1, tickLength: 5, tickPosition: 'inside', labels: { align: 'left', x: 8, }, }, { opposite: true, linkedTo: 0, lineWidth: 0, gridLineWidth: 0, title: { text: 'Acc', }, tickWidth: 1, tickLength: 5, tickPosition: 'inside', labels: { align: 'right', x: -8, }, }, ], legend: { enabled: false, }, plotOptions: { area: { states: { hover: { enabled: false, lineWidthPlus: 0, }, inactive: { opacity: 1, }, }, marker: { enabled: false }, fillOpacity: 0.2, lineWidth: 1, step: 'center', }, }, tooltip: { headerFormat: '<span style="font-size=10px;">Price: {point.key}</span><br/>', valueDecimals: 2, }, series: [ { name: 'Bids', data: this.getBidOrders(), step: 'left', }, { name: 'Asks', data: this.getAskOrders(), color: '#fc5857', step: 'right', }, ], }; } getBidOrders() { // 从props或内部状态获取最新买盘数据 return this.props.bids || []; } getAskOrders() { // 从props或内部状态获取最新卖盘数据 return this.props.asks || []; } // 示例:设置数据更新监听 // setupDataListener() { // // 假设通过WebSocket获取实时数据 // const ws = new WebSocket('your-data-endpoint'); // ws.onmessage = (event) => { // const { bids, asks } = JSON.parse(event.data); // // 更新props(如果用Redux或父组件传值)或内部状态 // this.props.updateMarketData(bids, asks); // }; // } render() { return ( <div id='chartContainer'> <HighchartsReact highcharts={Highcharts} options={this.state.chartOptions} allowChartUpdate={true} /> </div> ); } }
方法2:直接操作Highcharts实例更新数据
通过ref获取图表实例,直接调用Highcharts API更新系列数据,性能更优,避免组件重渲染:
class MarketDepth extends React.Component<Props, State> { chartRef = React.createRef(); state = { selectedBid: null, selectedAsk: null, interval: null }; componentDidMount() { // 启动数据更新监听 this.setupDataListener(); } setupDataListener() { // 模拟实时数据更新(实际项目替换为WebSocket等) const interval = setInterval(() => { const newBids = this.getBidOrders(); const newAsks = this.getAskOrders(); this.updateChart(newBids, newAsks); }, 2000); this.setState({ interval }); } componentWillUnmount() { // 组件卸载时清除定时器 if (this.state.interval) clearInterval(this.state.interval); } updateChart(newBids, newAsks) { const chart = this.chartRef.current?.chart; if (!chart) return; // 更新买盘数据,第二个参数设为false避免多次重绘 chart.series[0].setData(newBids, false); // 更新卖盘数据,第二个参数设为true完成重绘 chart.series[1].setData(newAsks, true); // 同步更新平均价格线 chart.xAxis[0].update({ plotLines: [{ color: '#FFFFFF', width: 1, value: this.getAverageLine(), label: { text: 'Actual price', rotation: 90, align: 'right', style: { fontStyle: 'italic', }, }, }] }); } // 原图表配置保持不变 chartOptions = { /* ... 原配置内容 ... */ }; getBidOrders() { ... } getAskOrders() { ... } render() { return ( <div id='chartContainer'> <HighchartsReact highcharts={Highcharts} options={this.chartOptions} ref={this.chartRef} allowChartUpdate={true} /> </div> ); } }
关键注意事项
- 原代码中
chartOptions是类的静态属性,不会随数据更新重新生成,必须让配置动态生成或直接操作实例。 - 修正了原代码中
fonstStyle的拼写错误,改为fontStyle。 - 确保
allowChartUpdate={true}(默认值为true,显式声明更清晰),允许Highcharts React更新图表。
内容的提问来源于stack exchange,提问作者Andrei Călugăr
相关产品推荐
相关产品推荐

