wuba / react-native-echarts

📈 React Native ECharts Library: An awesome charting library for React Native, built upon Apache ECharts and leveraging react-native-svg and react-native-skia. Offers significantly better performance compared to WebView-based solutions.
https://wuba.github.io/react-native-echarts/
Apache License 2.0
682 stars 24 forks source link

Sync prop changes #141

Closed alexey-yarmosh closed 6 months ago

alexey-yarmosh commented 6 months ago

I am using an example component from the https://wuba.github.io/react-native-echarts/docs/getting-started/write-a-dynamic-data-chart with the difference that my data is coming from props. Upper component updates values every second.

The bug is that after the emulator opens, I can see that chart rerenders fully every second, which is reasonable. But in ~5 seconds I see an error:

image

As I understand, chart is not supposed to be rerendered on every props change. Instead rerender should be canceled and something like chart.setOption() called in the meantime. If that is true can you please provide an example? I guess that is a general usage for many users to get the data from the upper state and sync it over time.

alexey-yarmosh commented 6 months ago

Ok, after some searching on other github repos solution seems to be:

const [chartInstance, setChartInstance] = useState<EChartsType | null>(null);
  const skiaRef = useRef(null);

  useEffect(() => {
    let chart: EChartsType | null = null;
    if (skiaRef.current && !chartInstance) {
      chart = echarts.init(skiaRef.current, 'light', {
        renderer: 'svg',
        width: E_WIDTH,
        height: E_HEIGHT,
      });
      chart.setOption(options);
      setChartInstance(chart);
      return () => chart?.dispose();
    }
  }, []);

  useEffect(() => {
    chartInstance?.setOption(options);
  }, [data]);

Hope that is correct implementation. Original link: https://github.com/windalfin/fasttt/blob/ff30b40a040700e5fc99f807fa96cda3951ca01d/src/components/HomePage/FastingProgressGauge.tsx#L86-L105

yechunxi commented 6 months ago

Ok, after some searching on other github repos solution seems to be:

const [chartInstance, setChartInstance] = useState<EChartsType | null>(null);
  const skiaRef = useRef(null);

  useEffect(() => {
    let chart: EChartsType | null = null;
    if (skiaRef.current && !chartInstance) {
      chart = echarts.init(skiaRef.current, 'light', {
        renderer: 'svg',
        width: E_WIDTH,
        height: E_HEIGHT,
      });
      chart.setOption(options);
      setChartInstance(chart);
      return () => chart?.dispose();
    }
  }, []);

  useEffect(() => {
    chartInstance?.setOption(options);
  }, [data]);

Hope that is correct implementation. Original link: https://github.com/windalfin/fasttt/blob/ff30b40a040700e5fc99f807fa96cda3951ca01d/src/components/HomePage/FastingProgressGauge.tsx#L86-L105

@alexey-yarmosh Did this approach solve your problem? This is the correct implementation. When options change, instead of re-creating the echart instance, directly call setOption to re-render the chart.

However, some users still find that page switching is too fast and errors occasionally occur. After the echart instance is destroyed, some internal operations may continue to cause errors. like this discussion. We also submitted a PR to zrender to solve the change problem, but the PR is still waiting for official verification and merging.

alexey-yarmosh commented 6 months ago

Yes, seems to be working for now. If some issues arise I'll get back here. Also probably that usage worth documenting on the website, I can assist with that if needed.

yechunxi commented 6 months ago

Yes, seems to be working for now. If some issues arise I'll get back here. Also probably that usage worth documenting on the website, I can assist with that if needed.

Thank you for your suggestion. Welcome to submit a PR to write the document. This way you can provide more examples. This issue will be closed. If you have other questions, welcome to open a new issue.