• React魔法堂:echarts-for-react源码略读


    前言

    在当前工业4.0和智能制造的产业升级浪潮当中,智慧大屏无疑是展示企业IT成果的最有效方式之一。然而其背后怎么能缺少ECharts的身影呢?对于React应用而言,直接使用ECharts并不是最高效且优雅的方式,而echarts-for-react则是针对React应用对ECharts进行轻量封装和增强的工具库。

    echarts-for-react的源码非常精简,本文将针对主要逻辑分析介绍。

    从与原生初始化对比开始

    原生ECharts中我们会通过如下代码初始化图表实例

    <div id="container" style="width: 100px; height: 100px">div>
    <script>
      const chart = echarts.init(document.getElementById('container'))
    script>
    

    那么生成的HTML Element结构为

    <div id="container" style="width: 100px; height: 100px" _echarts_instance=".....">
      <div style="width: 100px; height: 100px;position: relative;">
        <canvas width="100" height="100">canvas>
      div>
    div>
    

    其中第二层的div和canvas的宽高默认为容器div#container的宽高,我们可以通过init入参指定两者宽度。

    const chart = echarts.init(
      document.getElementById('container'), 
      null, 
      { 
        width: 300, // 可显式指定实例宽度,单位为像素。如果传入值为null/undefined/'auto',则表示自动取 dom(实例容器)的宽度
        height: 300 // 可显式指定实例高度,单位为像素。如果传入值为null/undefined/'auto',则表示自动取 dom(实例容器)的高度
      }
    )
    

    注意:若此时容器div#container尺寸发生变化,第二层div和canvas尺寸并不会自适应,需要我们手工调用chart.resize()触发。

    而通过echarts-for-react上述步骤将被简化为如下,并且生成相同的HTML Element结构:

    import ReactECharts from 'echarts-for-react'
    
    function Demo() {
      return (
        <ReactECharts
          style={{width: 100, height: 100}} // 设置容器的宽高
          autoResize={true} // 默认为true,自动监测容器尺寸的变化,并调用`chart.resize()`
        />
      )
    }
    

    陷阱-默认值height为300px

    由于ReactEChartsstyle默认内置height: 300,源码如下:

    // src/core.tsx
    
    render(): JSX.Element {
      const { style, className = '' } = this.props
      const newStyle = { height: 300, ...style }
    
      return (
        <div
          ref={(e: HTMLElement) => {
            this.ele = e
          }}
          style={newStyle}
          className={`echarts-for-react ${className}`}
        />
      )
    }
    

    因此通过className的方式设置容器高度时必须使用!important

    <ReactECharts
      className={styles.container}
    />
    
    // index.module.css
    .container {
      height: 500px !important;
    }
    

    获取ECharts实例

    const ref = useRef()
    
    useEffect(() => {
      const instance = ref.current.getEchartsInstance()
    }, [])
    
    <EchartsReact
      ref={ref}
    />
    

    主逻辑源码剖析

    核心逻辑均在EChartsReactCore组件上(位于文件src/core.tsx),特点如下:

    1. 采用PureComponent方式编写组件以便适配所有React版本;
    2. 仅对ECharts 命令式API进行声明式API的封装,并没有将每种EChart图表类型封装为组件;
    3. 添加特性,监测容器尺寸的变化,并自动调用ECharts实例的resize方法实现自适应。

    挂载渲染过程

    1. componentDidMount时调用renderNewEcharts方法执行ECharts组件的生成逻辑;
    2. renderNewEcharts方法内部逻辑
      1. 通过echarts.getInstanceByDom(容器DOM元素)echarts.init(容器DOM元素,主题,配置)获取已有ECharts实例或生成新的ECharts实例;
      2. 通过ECharts实例的setOption方法设置或更新图表内容;
      3. 通过ECharts实例的showLoadinghideLoading控制图表渲染前是否显示加载进度条;
      4. 将通过props onEvents配置的ECharts支持的事件处理器绑定到ECharts实例上;
      5. 触发props onChartsReady 方法;
      6. 订阅通过size-sensor监测容器尺寸并自动调用ECharts实例的resize方法,实现图表尺寸的自适应。

    更新渲染过程

    由于render方法无论执行多少遍,实际上仅仅有可能影响容器本身而已,对ECharts实例并没有任何影响。因此实际影响ECharts实例的逻辑被放置到componentDidUpdate那里,这做法和react-amap中在useEffect中通过Marker等实例内置的set方法更新状态的原理是一致的。

    1. 若更新的props包含theme, optsonEvents则要销毁原来的ECharts实例,重新构建一个新的ECharts实例,并终止更新渲染过程;否则执行第2步。
    2. 若props中的option,notMergela,lazyUpdate,showLoadingloadingOption均没有变化,则不更新ECharts实例;
      注意:EChartsReactCore继承PureComponent,若上述props进行shallow equal比较为true时也不会更新ECharts实例;但这一步采用deep equal比较,来减少ECharts实例的更新。
    3. 若props中的styleclassName发生变化则会触发ECharts实例的resize方法。

    卸载过程

    1. 取消通过size-sensor订阅的容器尺寸变化事件;
    2. 通过ECharts实例的dispose方法注销ECharts实例。

    项目依赖

    • fast-deep-equal: 遍历对象属性进行对比
    • size-sensor: DOM元素尺寸监听器,当元素尺寸变化时会触发回调函数

    后续

    echarts-for-react利用size-sensor实现图表尺寸自适应容器尺寸,那么size-sensor是怎样做到这一点呢?敬请期待一下篇《React魔法堂:size-sensor源码略读》。

    尊重原创,转载请注明来自:https://www.cnblogs.com/fsjohnhuang/p/16792575.html _肥仔John

  • 相关阅读:
    高新技术企业申报时企业提交材料前这些细节
    js摄像头动态检测
    【笔记】:更方便的将一个List中的数据传入另一个List中,避免多重循环
    B. AND 0, Sum Big-Codeforces Round #716 (Div. 2)
    Day 88
    IIS发布.net网站(配置Nginx以及HTTP和HTTPS)
    [H5动画制作系列 ] Sprite Demo 的两种方法
    数据分析_数据分析思维(1)
    3.7 Android eBpf Hello World调试(一)
    express-generator快速构建node后端项目
  • 原文地址:https://www.cnblogs.com/fsjohnhuang/p/16792575.html