提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
There is a chart instance already initialized on the dom.消除
React
中使用echarts
的注意点
我们在React
中使用echarts
,可以比较方便的将图图表封装成react
组件,但值得注意的一点是,echarts
图表的更新和react
组件重新渲染(render
)是不一致的,有可能存在冲突。如果不注意,可能会同时渲染出好几份图表的副本,直接导致的一个问题是onClick
等回调函数会被一次事件触发多次,消耗很多系统资源。
比如说下面的代码,封装了一个散点图组件。
import * as echarts from 'echarts';
import { useEffect } from 'react';
export const Scatter = (props) => {
useEffect(() => {
var chartDom = document.getElementById('main-scatter');
var myChart = echarts.init(chartDom);
var option = {
xAxis: {},
yAxis: {},
series: [
{
symbolSize: 20,
data: props.data, // 这里需要坐标的列表,如 [[1,2], [3,4]]
type: 'scatter'
}
]
};
myChart.setOption(option);
}, [props.data]) // 坐标更新时组件随之更新
return (
<div id="main-scatter" style={{ width: "400px", height: "400px", display: "block" }}>
</div>
)
}
而如果这个组件被React
重新渲染,则会报warning:
There is a chart instance already initialized on the dom.
对这个问题,也是在网上找了好久,有人说给setOption
加false
参数,表示重新绘图;或者用echarts.dispose
删除document.getElementById
拿到的DOM。前者无效,后者导致页面重新渲染时这个DOM失去了width
和height
属性,导致图表撑不起来。
正解
正确的做法之一是用echarts.getInstanceByDom
获取之前可能创建过的实例,如果有则继续使用这个实例,否则创建,上面的代码只要稍微改动一下:
import * as echarts from 'echarts';
import { useEffect } from 'react';
export const Scatter = (props) => {
useEffect(() => {
var chartDom = document.getElementById('main-scatter');
// 获取实例
var myChart = echarts.getInstanceByDom(chartDom);
if (!myChart) // 如果不存在则创建
{
myChart = echarts.init(chartDom);
}
var option = {
xAxis: {},
yAxis: {},
series: [
{
symbolSize: 20,
data: props.data, // 这里需要坐标的列表,如 [[1,2], [3,4]]
type: 'scatter'
}
]
};
myChart.setOption(option);
}, [])
return (
<div id="main-scatter" style={{ width: "400px", height: "400px", display: "block" }}>
</div>
)
}
这样问题就解决了,当然还是会遇到重复触发点击事件的情况,是这样解决的:
myChart.off("click").on('click', (param) => {
props.handleGraphClick(param);
});