好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

由于 ReactECharts 的 style 默认内置 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 ),特点如下:

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

挂载渲染过程

在 componentDidMount 时调用 renderNewEcharts 方法执行ECharts组件的生成逻辑; renderNewEcharts 方法内部逻辑

通过 echarts.getInstanceByDom(容器DOM元素) 或 echarts.init(容器DOM元素,主题,配置) 获取已有ECharts实例或生成新的ECharts实例;

通过ECharts实例的 setOption 方法设置或更新图表内容;

通过ECharts实例的 showLoading 或 hideLoading 控制图表渲染前是否显示加载进度条;

将通过props  onEvents 配置的ECharts支持的事件处理器绑定到ECharts实例上;

触发props  onChartsReady  方法;

订阅通过 size-sensor 监测容器尺寸并自动调用ECharts实例的 resize 方法,实现图表尺寸的自适应。

更新渲染过程

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

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

卸载过程

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

项目依赖

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

后续

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

到此这篇关于React之echarts-for-react源码解读的文章就介绍到这了,更多相关echarts-for-react源码内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

查看更多关于React之echarts-for-react源码解读的详细内容...

  阅读:33次