React-redux开发之echarts组件封装

#1

谈一下react开发如何使用echarts。

echarts是个好东西,很强大的配置功能,很多开发者都在使用它。那么在react里面如何去调用echarts?如何封装echarts呢?

react开发者,首先会想到的是上github搜索“react echarts”,然后找最多start的那个插件,比如“echarts-for-react”,那么,我们是不是真的有必要用插件来做呢?

带着上面这些疑问,下面我将一个个给大家解答开发中的一些体会。

1、是不是应该使用别人封装好的react-echarts插件?

这个答案没有绝对的标准,我觉得不需要第三方的react-echarts插件,使用echarts官方的插件即可实现我们需要的功能。

echarts很庞大,每种类型的图标都是一个单独的组件,还有各种小插件,比如label、title等,或许你应该看看这个教程:在webpack中使用echarts

这个官方教程提到了一点很重要,为了避免我们引用过于庞大的echarts源文件,可以采用模块化加载的方式。

// 引入 ECharts 主模块
var echarts = require('echarts/lib/echarts');
// 引入柱状图
require('echarts/lib/chart/bar');
// 引入提示框和标题组件
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');

2、如何在react中封装echarts组件?

react完完全全就是组件化开发,跟echarts可以很好的切合,以封装pie图为例。

a、我们首先要新建一个pieReact.js文件(你想用jsx或者ts为后缀也可以)。

b、添加基本的react组件模型,一个render方法,定义了一个div容器来展示canvas,style初始化容器的宽度和高度,如果不设置,就无法渲染canvas,这里用到了ref来获取节点,而不是id。

import React, { Component } from 'react';

export class PieReact extends React.Component {
    
    render() {
        return (
            <div className="pie-react">
                <div ref="pieReact" style={{width: "100%", height: "200px"}}></div>
            </div>
        )
    }
}

c、请问你安装好了echarts了吗?没有就请安装。

npm install echarts --save-dev

d、在pieReact组件中导入echarts,每个echarts小插件的导入方式可以参考:echarts组件导入方式

import React, { Component } from 'react';

//导入echarts
var echarts = require('echarts/lib/echarts') //必须
require('echarts/lib/chart/pie') //图表类型
require('echarts/lib/component/title') //标题插件

export class PieReact extends React.Component {
    
    render() {
        return (
            <div className="pie-react">
                <div ref="pieReact" style={{width: "100%", height: "200px"}}></div>
            </div>
        )
    }
}

e、那我们要怎么初始化echarts呢?在react中,我们需要等到虚拟dom渲染完成了才能通过refs去获取节点,这样我们就可以在组件componentDidMount的时候初始化echarts。

import React, { Component } from 'react';

//导入echarts
var echarts = require('echarts/lib/echarts') //必须
require('echarts/lib/chart/pie') //图表类型
require('echarts/lib/component/title') //标题插件

export class PieReact extends React.Component {
    
    componentDidMount() {
        const { data } = this.props //外部传入的data数据
        let myChart = echarts.init(this.refs.pieChart) //初始化echarts

        //我们要定义一个setPieOption函数将data传入option里面
        let options = this.setPieOption(data)
        //设置options
        myChart.setOption(options)
    }
    
    render() {
        return (
            <div className="pie-react">
                <div ref="pieReact" style={{width: "100%", height: "200px"}}></div>
            </div>
        )
    }
}

f、添加setPieOption函数,只返回一个纯对象。在constructor绑定setPieOption到当前的实例。

import React, { Component } from 'react';

//导入echarts
var echarts = require('echarts/lib/echarts') //必须
require('echarts/lib/chart/pie') //图表类型
require('echarts/lib/component/title') //标题插件

export class PieReact extends React.Component {
    
    constructor(props) {
        super(props)
        this.setPieOption = this.setPieOption.bind(this)
    }
    
    componentDidMount() {
        const { data } = this.props //外部传入的data数据
        let myChart = echarts.init(this.refs.pieChart) //初始化echarts

        //我们要定义一个setPieOption函数将data传入option里面
        let options = this.setPieOption(data)
        //设置options
        myChart.setOption(options)
    }
    
    render() {
        return (
            <div className="pie-react">
                <div ref="pieReact" style={{width: "100%", height: "200px"}}></div>
            </div>
        )
    }
    
    //一个基本的echarts图表配置函数
    setPieOption(data) {
        return {
            series : [
                {
                    name: '比例',
                    type: 'pie',
                    radius: ['70%', '90%'],
                    avoidLabelOverlap: true,
                    data: data, //传入外部的data数据
                    label: {
                        normal: {
                            show: false,
                            position: 'center',
                            textStyle: {
                                fontSize: '18'
                            },
                            formatter: "{d}% \n{b}",
                        },
                        emphasis: {
                            show: true,
                            textStyle: {
                                fontSize: '18',
                            }
                        }
                    },
                    labelLine: {
                        normal: {
                            show: false
                        }
                    }
                }
            ]
        }
    }
}

g、现在可以初始化显示一个echarts的pie图了,那么如果外部传入的data发生了改变怎么办呢?我们还需要添加一个方法来监听props的变化,幸运的是react已经帮我们做好了这些。使用componentDidUpdate()

import React, { Component } from 'react';

//导入echarts
var echarts = require('echarts/lib/echarts') //必须
require('echarts/lib/chart/pie') //图表类型
require('echarts/lib/component/title') //标题插件

export class PieReact extends React.Component {
    
    constructor(props) {
        super(props)
        this.setPieOption = this.setPieOption.bind(this)
    }
    
    componentDidMount() {
        const { data } = this.props //外部传入的data数据
        let myChart = echarts.init(this.refs.pieChart) //初始化echarts

        //我们要定义一个setPieOption函数将data传入option里面
        let options = this.setPieOption(data)
        //设置options
        myChart.setOption(options)
    }
    
    componentDidUpdate() {
        const { data } = this.props //外部传入的data数据
        let myChart = echarts.init(this.refs.pieChart) //初始化echarts

        //我们要定义一个setPieOption函数将data传入option里面
        let options = this.setPieOption(data)
        //设置options
        myChart.setOption(options)
    }
    
    render() {
        return (
            <div className="pie-react">
                <div ref="pieReact" style={{width: "100%", height: "200px"}}></div>
            </div>
        )
    }
    
    //一个基本的echarts图表配置函数
    setPieOption(data) {
        return {
            series : [
                {
                    name: '比例',
                    type: 'pie',
                    radius: ['70%', '90%'],
                    avoidLabelOverlap: true,
                    data: data, //传入外部的data数据
                    label: {
                        normal: {
                            show: false,
                            position: 'center',
                            textStyle: {
                                fontSize: '18'
                            },
                            formatter: "{d}% \n{b}",
                        },
                        emphasis: {
                            show: true,
                            textStyle: {
                                fontSize: '18',
                            }
                        }
                    },
                    labelLine: {
                        normal: {
                            show: false
                        }
                    }
                }
            ]
        }
    }
}

h、你会发现componentDidMount和componentDidUpdate执行的方法是一样的,那么我们可以提取出来作为一个单独的方法,然后在componentDidMount和componentDidUpdate调用即可。下面我们来看看代码的最终形态吧。

import React, { Component } from 'react';

//导入echarts
var echarts = require('echarts/lib/echarts') //必须
require('echarts/lib/chart/pie') //图表类型
require('echarts/lib/component/title') //标题插件

export class PieReact extends React.Component {
    
    constructor(props) {
        super(props)
        this.setPieOption = this.setPieOption.bind(this)
        this.initPie = this.initPie.bind(this)
    }
    
    initPie() {
        const { data } = this.props //外部传入的data数据
        let myChart = echarts.init(this.refs.pieChart) //初始化echarts

        //我们要定义一个setPieOption函数将data传入option里面
        let options = this.setPieOption(data)
        //设置options
        myChart.setOption(options)
    }
    
    componentDidMount() {
        this.initPie()
    }
    
    componentDidUpdate() {
        this.initPie()
    }
    
    render() {
        return (
            <div className="pie-react">
                <div ref="pieReact" style={{width: "100%", height: "200px"}}></div>
            </div>
        )
    }
    
    //一个基本的echarts图表配置函数
    setPieOption(data) {
        return {
            series : [
                {
                    name: '比例',
                    type: 'pie',
                    radius: ['70%', '90%'],
                    avoidLabelOverlap: true,
                    data: data, //传入外部的data数据
                    label: {
                        normal: {
                            show: false,
                            position: 'center',
                            textStyle: {
                                fontSize: '18'
                            },
                            formatter: "{d}% \n{b}",
                        },
                        emphasis: {
                            show: true,
                            textStyle: {
                                fontSize: '18',
                            }
                        }
                    },
                    labelLine: {
                        normal: {
                            show: false
                        }
                    }
                }
            ]
        }
    }
}

i、至于怎么动态改变this.props.data,就需要在外部组件做操作了,如果是定时器类型的更新,可以在action的ajax方法设置定时器去请求新的数据,如果是事件类型的更新(比如点击操作),就直接通过点击事件触发action去请求新数据。

j、在外部调用这个组件很简单,我只封装了一个data接口,更多接口的封装可以自己根据需要去做,比如颜色、字体大小自定义,定义标题,定位label等。

import { PieReact } from './PieReact'

//data的格式
/*
const data = [
    {value: 1, name: "是"},
    {value: 2, name: "否"}
]
*/

class Home extends React.Component {
    render () {
        const { data } = this.props.reducer
        <div>
            <PieReact 
                data={data}
            />
        </div>
    }
}

最后,提问环节。

小明同学:我只用了react,没用到redux,你说的action更新我都没有这个文件啊。

我:自己不会动动脑筋转个弯吗?好了,下课。

效果图

1 Like
#2

学习了,我之前都是无脑全扔在componentDidUpdate​:joy::joy:

#3

然后会出现什么情况呢

#4

没有什么副作用,就是感觉不太合理哈

#5

估计是你的强迫症又犯了。
不管黑猫白猫,抓到老鼠的就是好猫。

#6

哈哈,这话在理,不过能优雅的抓到耗子的猫比较装b :joy: 要做一只装b的猫

#7

我觉得做一只小白鼠更好

#8

666

#9

有兴趣可以加群一起交流交流

#10

求个群号

#11

也可用hightcharts实现 http://www.icafebolger.com/reactjs/reacthighchart1.html