echarts-for-react 源码分析

唐阳晖
2023-12-01

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 这个方法来完成图表必要内容的更新,核心的思想应是尽量判断出不需要更新的情况直接返回,减少更新频率。

 类似资料: