1、目录结构:
docs —— 文档,dumi
src
helper —— 工具文件夹
core.tsx —— 核心代码,EChartsReactCore 类
index.ts —— 继承 EChartsReactCore 类,初始化 echarts 为引入的 echarts 包
types.ts —— 主要是 EChartsReactProps
2、核心代码(core.tsx)解析
class EChartsReactCore :
属性:
ele —— charts 的元素属性,public
echarts —— echarts 实例,protected
方法:
constructor —— 构造函数,主要是初始化 ele (null) 和 echarts (props.echarts)
componentDidMount —— 挂载,调用 renderNewEcharts —— 渲染一个新的 echarts
componentDidUpdate —— 更新,传参是前一个参数对象,prevProps
componentDidUpdate(prevProps: EChartsReactProps) {
// 1、判断 props.shouldSetOption 方法的返回值,是否需要更新
const { shouldSetOption } = this.props;
if (isFunction(shouldSetOption) && !shouldSetOption(prevProps, this.props)) {
return;
}
// 2、以下属性修改的时候,需要 dispose 之后再新建
// 1). 切换 theme 的时候
// 2). 修改 opts 的时候
// 3). 修改 onEvents 的时候,这样可以取消所有之前绑定的事件 issue #151
if (
!isEqual(prevProps.theme, this.props.theme) ||
!isEqual(prevProps.opts, this.props.opts) ||
!isEqual(prevProps.onEvents, this.props.onEvents)
) {
this.dispose();
this.renderNewEcharts(); // 重建
return;
}
// 3、剩余的参数如果都没有改变,直接返回;否则调用 updateEchartsOption 方法,生成新的 echarts 实例
const pickKeys = ['option', 'notMerge', 'lazyUpdate', 'showLoading', 'loadingOption'];
if (!isEqual(pick(this.props, pickKeys), pick(prevProps, pickKeys))) {
this.updateEChartsOption();
}
// 4、判断 style 和 className 有没有改变,更新样式
if (!isEqual(prevProps.style, this.props.style) || !isEqual(prevProps.className, this.props.className)) {
this.resize();
}
}
componentWillUnmount —— 卸载,调用 dispose 函数
public 方法:
getEchartsInstance —— 获取 echarts 实例,不存在的话 new 一个新的(调用 echarts 的 init 方法)
private 方法:
dispose —— 析构,清除 size-sensor 监听,调用 echarts 的 dispose 方法
renderNewEcharts —— 渲染一个新的 echarts
bindEvents —— 事件绑定,只绑定实例 events 上的属性(in & hasOwnProperty)
// bind the events
private bindEvents(instance, events: EChartsReactProps['onEvents']) {
function _bindEvent(eventName: string, func: Function) {
// ignore the event config which not satisfy
if (isString(eventName) && isFunction(func)) {
// binding event
instance.on(eventName, (param) => {
func(param, instance);
});
}
}
// loop and bind
for (const eventName in events) {
if (Object.prototype.hasOwnProperty.call(events, eventName)) {
_bindEvent(eventName, events[eventName]);
}
}
}
updateEChartsOption:更新 option
private updateEChartsOption(): EChartsInstance {
const { option, notMerge = false, lazyUpdate = false, showLoading, loadingOption = null } = this.props;
// 1. 获取实例
const echartInstance = this.getEchartsInstance();
// 2. 设置 option
echartInstance.setOption(option, notMerge, lazyUpdate);
// 3. 设置 loading mask
if (showLoading) echartInstance.showLoading(loadingOption);
else echartInstance.hideLoading();
// 4、返回 echarts 实例
return echartInstance;
}
主要的两个方法 —— init 方法和 dispose 方法都是调用 echarts 的,echarts-for-react 只是对一些内容进行了包装。
3、总结
可以看出来 echarts-for-react 的源码不复杂,就是封装了 echarts。通过 updateEChartsOption 这个方法来完成图表必要内容的更新,核心的思想应是尽量判断出不需要更新的情况直接返回,减少更新频率。