在 React 中同步两个 EChart 之间的缩放状态会导致缩放“快速返回”

问题描述 投票:0回答:1

我正在 React 应用程序中使用 ECharts,在同步两个折线图之间的缩放状态时遇到了问题。所需的行为是,当一个图表的缩放发生更改时,另一个图表应反映相同的缩放级别。然而,我发现在调整一张图表上的缩放后,它似乎“弹回”到其原始位置。

这是代码的简化表示:

// LineChart.tsx

export const LineChart = React.forwardRef<ReactECharts, LineChartProps>((props, ref) => {
  { zoomState, onDataZoom } = props

  const option: EChartsOption = {
    dataZoom: [{
      type: 'slider',
      start: zoomState.start,
      end: zoomState.end,
    }],
  }

  return (
    <ReactECharts 
      ref={ref} 
      option={option}
      onEvents={{
        'datazoom': onDataZoom,
      }}
    />
  );
});

// index.tsx

const [zoomState, setZoomState] = useState<{start: number, end: number}>({ start: 80, end: 100 });

function onDataZoom(params: any) {
    const newZoom = { start: params.start, end: params.end };
    setZoomState(newZoom);
}

var co2Chart = (
    <LineChart 
      ref={co2ChartRef}
      data={device.deviceData}
      zoomState={zoomState}
      onDataZoom={onDataZoom}
      valueToPlot={'co2'}
      // ... (rest of the props)
    />
)

var tempChart = (
    <LineChart 
      ref={tempChartRef}
      data={device.deviceData}
      zoomState={zoomState}
      onDataZoom={onDataZoom}
      valueToPlot={'temperature'}
      // ... (rest of the props)
    />
)

根据我的观察:

  • 启动缩放更改(通过拖动一张图表上的缩放滑块)后,将触发 datazoom 事件。
  • onDataZoom 函数尝试设置新的缩放状态。
  • 在 React 更新状态并重新渲染组件之前,由于 ECharts 的内部行为,LineChart 组件似乎会重新渲染。
  • 由于状态尚未更新,图表恢复到旧的缩放状态,触发另一个 datazoom 事件。
  • 这似乎创建了一个反馈循环,导致“快速恢复”效果。

我仍在学习 React,虽然我认为我明白发生了什么,但我不知道如何解决它。

reactjs react-hooks echarts
1个回答
0
投票

我通过为 onDataZoom 函数实现去抖动技术成功解决了缩放“回弹”问题。这种策略有效地打破了 React 的异步状态更新和 ECharts 自己的渲染周期之间的反馈循环。

为什么去抖动有效

当您在 ECharts 中拖动缩放滑块时,datazoom 事件会快速连续触发多次。这些事件中的每一个通常都会触发 React 状态更新,从而由于 ECharts 和 React 之间的反馈循环而导致不必要的行为。对 onDataZoom 函数进行反跳会限制它的调用速率,本质上是在实际运行原始函数之前等待一段时间,而没有任何新的调用。这为 React 提供了足够的时间来更新其状态并重新渲染组件,从而有效地同步两个图表之间的缩放状态。

// index.tsx
import { debounce } from 'lodash';

function onDataZoom(params: any) {
  const newZoom = { start: params.start, end: params.end };
  setZoomState(newZoom);
}

const debouncedOnDataZoom = debounce(onDataZoom, 200);

var co2Chart = (
  <LineChart 
    data={device.deviceData}
    zoomState={zoomState}
    onDataZoom={debouncedOnDataZoom}
    valueToPlot={'co2'}
  >
)
© www.soinside.com 2019 - 2024. All rights reserved.