React ApexChart更新选项时如何保持缩放级别不重置?
问题
使用React ApexChart展示数据,设置开关控制数据标签的显示/隐藏,修改选项时图表缩放级别会被重置。如何在React中实现更新选项时保留缩放级别?是否需要改用原生ApexChart实现?
组件示例代码
import Chart from "react-apexcharts"; import React, { useEffect, useState } from 'react'; import { Layout } from "antd"; interface Props { series?: ApexAxisChartSeries; chartOptiosn?: Record<string, any>; [ key: string ]: any; } export const DynamicChart: React.FC<Props> = React.memo( ( props: Props ) => { const { Content } = Layout; const { series, chartOptions, uuid } = props; const [ initialRerender, setInitialRerender ] = useState( false ); useEffect( () => { if ( !initialRerender ) { setInitialRerender( true ); } }, [ initialRerender ] ); useEffect( () => { }, [] ); useEffect( () => { console.log( chartOptions ); }, [ chartOptions ] ); return ( <Layout> <Content> <Chart options={ { ...structuredClone( chartOptions || {} ), chart: { ...chartOptions.chart, id: uuid } } } series={ series } type="area" height={ 350 } /> </Content> </Layout> ); } );
图表配置选项
export const defaultOptions: ApexCharts.ApexOptions = { series: [], chart: { animations: { enabled: true, easing: "linear", dynamicAnimation: { speed: 300 } }, toolbar: { show: true, tools: { download: `<svg viewBox="64 64 896 896" focusable: "false" name= "download" theme="outlined"><path d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg>`, selection: false, zoom: true, zoomin: true, zoomout: true, pan: true, customIcons: [] }, }, zoom: { enabled: true } }, dataLabels: { enabled: false }, yaxis: { labels: { style: { fontSize: "14px", fontWeight: 600, colors: [ "#8c8c8c" ], }, }, }, xaxis: { type: "datetime" } };
解决方案
不需要改用原生实现,通过以下方式可在React中保留缩放状态:
1. 核心思路
问题根源是每次更新chartOptions时,组件传递了新的options对象导致图表重新初始化,丢失缩放状态。解决方案是直接操作图表实例,保存并恢复缩放范围。
2. 修改后的组件代码
import Chart from "react-apexcharts"; import React, { useEffect, useRef, useState } from 'react'; import { Layout } from "antd"; interface Props { series?: ApexAxisChartSeries; chartOptions?: Record<string, any>; [key: string]: any; } export const DynamicChart: React.FC<Props> = React.memo((props: Props) => { const { Content } = Layout; const { series, chartOptions, uuid } = props; const chartRef = useRef<{ chart: ApexCharts }>(null); // 保存当前缩放的X轴范围 const [savedXRange, setSavedXRange] = useState<{ min: number; max: number } | null>(null); // 监听缩放/平移事件,保存当前范围 const handleZoomPan = () => { if (!chartRef.current) return; const xAxis = chartRef.current.chart.xaxis; setSavedXRange({ min: xAxis.min, max: xAxis.max }); }; // 更新图表选项时,保留缩放状态 useEffect(() => { if (!chartRef.current || !chartOptions) return; // 先更新选项,第三个参数设为false表示不重置缩放 chartRef.current.chart.updateOptions(chartOptions, false, false); // 如果有保存的缩放范围,恢复 if (savedXRange) { chartRef.current.chart.updateOptions( { xaxis: { min: savedXRange.min, max: savedXRange.max } }, true, // 重绘图表 false // 不重置缩放状态 ); } }, [chartOptions]); // 更新系列数据时,保留缩放状态 useEffect(() => { if (!chartRef.current || !series) return; chartRef.current.chart.updateSeries(series, false); if (savedXRange) { chartRef.current.chart.updateOptions( { xaxis: { min: savedXRange.min, max: savedXRange.max } }, true, false ); } }, [series]); return ( <Layout> <Content> <Chart ref={chartRef} options={{ ...chartOptions || {}, chart: { ...chartOptions?.chart, id: uuid, events: { zoom: handleZoomPan, pan: handleZoomPan } } }} series={series} type="area" height={350} /> </Content> </Layout> ); });
3. 关键细节说明
- 使用
useRef获取图表实例,直接调用原生updateOptions和updateSeries方法,避免组件重新渲染导致实例重建 - 在
zoom和pan事件中保存当前X轴的缩放/平移范围 - 调用
updateOptions时,第三个参数设为false,表示不重置缩放状态 - 去掉
structuredClone,避免创建新的options对象触发不必要的组件更新
内容的提问来源于stack exchange,提问作者Andy95
相关产品推荐
相关产品推荐

