Close More (Vert) Close

React is a fairly new front-end JavaScript library that is developed and used by Facebook. While it is often cited as an alternative to modern JS MVC libraries such as AngularJS, React is not a full fledged MVC framework.

Rather, React is more of a component library allowing developers to create reusable, encapsulated components to be shared across an application. There is no long ramp-up time for development and a user can be proficient with React within a day or two of using it.

Given React’s explosive uptake in the JS community and our interest in using it internally at ZingChart, the development team decided to create a component for including interactive charts into React projects.

Throughout this tutorial, we will be utilizing Codepen to display examples.

Part 0 - The 10 minute React primer

reactjs logo
This article does not include a deep dive into React's features. However, we will touch on the necessities for those unfamiliar with React. If you are familiar with React, feel free to skip this section and proceed to Part 1.

Classes

Code :

<script type="text/jsx">
var MyComponent = React.createClass({  
        render : function(){  
            var str = "World";  
            return(  
              <div>Hello {str}</div>  
            );  
        }  
    });  
    ReactDOM.render(<MyComponent />, document.body);  
</script>  

Output:

<div>Hello World</div>  

Try it:

See the Pen React - Hello World by ZingChart (@zingchart) on CodePen.

Classes are the building blocks of React. In the code snippet above, we see that a new class <MyComponent/> is created and has a single render() method. Inside the render method, a private variable str is assigned the value of "World".

Finally the render method returns markup which injects the private variable inside of the div using React's binding notation { }. To render the element to the view, we simply call the top level method ReactDOM.render, passing in the React class we just created along with an insertion point, document.body.

“What's with that weird markup inside my JavaScript?”

JSX

JSX is an XML-like syntax that allows developers to define React components. It also provides a way to intermix React and Native DOM elements together. Having markup inside of JavaScript may look strange, but it allows a clean way to compose and visualize elements without having to use a series of functions to create and style elements.

To illustrate this even further, below are examples of how to create a dynamic <select> tag in plain/vanilla JavaScript compared to React and JSX.

Vanilla :

function createSelect(){  
    var types = ['one', 'two', 'three'];  
    var _select = document.createElement('select');  
    _select.className = "blueselect";  
    for(var i = 0; i < types.length; i++){  
        var _opt = document.createElement('option');  
        _opt.value = types[i];  
        _opt.innerHTML = types[i];  
        _select.appendChild(_opt);  
    }  
    return _select;  
}  
(document.getElementById('vanilla')).appendChild(createSelect());  

React and JSX:

var MySelect = React.createClass({  
    render : function(){  
        var types = ['one', 'two', 'three'];  
        var options = types.map(function(opt){  
            return({opt}  
            );  
        });  
        return(<select>  
                {options}  
            </select>  
        );  
    }  
});  
ReactDOM.render(, document.getElementById('react'));  

Try it:

See the Pen React - Hello World - 2 by ZingChart (@zingchart) on CodePen.

In both code snippets, we create similar select elements with three options in them:
  • In the vanilla JavaScript snippet, we call the native DOM manipulation functions to create elements, attach values and attributes, and append them to each other.

  • In the React snippet, we have a single render function that loops through some array and returns JSX markup along with where to insert context { } in each loop.

Vanilla JavaScript Advantages:

  • Zero dependencies.

  • Fastest execution possible. All frameworks decompose down to native functions eventually.

  • No ramp-up time (unless you don't know plain JavaScript).

JSX Advantages:

  • Readability. Allowing markup inside of logic allows for a reader to quickly guess what that function does without fully analyzing the function.

  • Maintainability. If your developers use React, they can extend features and narrow down bugs fairly easily since each component is encapsulated.

JSX works beautifully when creating and inheriting components within each other. While it may scare off some business logic-markup separation purists, there is a logical reason of why Facebook strongly recommends using it alongside React.

Note:  React does give us the option to forgo JSX and use React DOM functions entirely. It's a bit out of scope for this article to go into detail, but as a fair warning : It's a mess without JSX.

Props and State

To communicate between components inside of React, we can pass literals and objects through props and state. Props differ from state in that the values are changed automagically through the inheritance setup by each component. Meanwhile, state is changed within a single component to:

  • Trigger state change

  • Re-render

  • Propagate the changes to its children

It is common to see state handled by a single parent component and props as a way to trickle down information to children components.

apple
For illustrative purposes, below is an example of a component called <Tree/> and another called <Apple/>.

See the Pen Simple React Example by ZingChart (@zingchart) on CodePen.

Dissecting each part of this snippet will provide a better understanding of the flow, starting with the <Tree/> Class.

Tree.getInitialState

We can think of this hierarchy in the way a tree has an apple. Inside of the <Tree/> class, the getInitialState method initializes the state object with a single property alive with the value of false. This will indicate if the <Tree/> is alive or not, and will determine if its virtual apples are ripe or not.

Tree.render

Next in the snippet is the render method. There is a <div> as a single container and two child elements. React requires each component to have one single parent element.

The button sets a function toggleTreeState() to be executed on the onClick event and has a boolean expression to change the button's text to the state of the tree.

Note that the expression returns a string and is wrapped around the binding notation delimited by { }. React will know to insert the evaluated expression's value directly in the binding.

Tree.toggleTreeState

The next part of the snippet contains the toggleTreeState() method. This is a method we have created to control state logic. Its responsibility is to invert our boolean property alive by passing the instance's setState() method an object with the updated state.

Every time this function is called (by way of the button we created), the instance of <_Tree/>_ state value will change as well as anything in the view that relies on state. This means our button's text will change automatically through our one-way binding. All of this handled for us by React, which is pretty slick.

Apple

Moving onto the <Apple/> class, we are simply returning a <div> that displays if one of our virtual apples is ripe or rotten, based on the  boolean expression {(this.props.ripe)?'ripe' : 'rotten'}.

The props object is populated with properties and values that were visible during instantiation. Looking back inside of the Tree class's render method, a property ripe was declared on the <Apple/> component and passed a state value from the instance of a Tree. This allows the <Apple/> to be completely dependent on the tree's state, only referring to its props object.

Why didn’t we make ripe a state instead of a prop? We simply wanted an <Apple/> to either be ripe or rotten depending on the result of our parent, the <Tree/>, without having to change an Apple’s state manually. Therefore, Apple.ripe is dependent upon Tree.alive.

See the Pen React - Hello World - 3 by ZingChart (@zingchart) on CodePen.

This structure proves to be extremely useful and a great way to architecturally separate state logic in an application. Determine the highest point in a hierarchy where a state should live, and trickle down its effects via props. If you would like to learn more about React, the official docs will get you up to speed quickly. https://facebook.github.io/react/docs/jsx-in-depth.html

Part 1 - A ZingChart Component for React

ZingChart React Component
The rest of this article will focus on how to use React and ZingChart together. We will assume you have a basic understanding of each technology as we walk through each step. To start off, we attempt to create a simple <ZingChart/> component.

var ZingChart = React.createClass({  
    render : function(){  
        return (  
            <div id={this.props.id}></div>  
        );  
    },  
    //Called after the render function.  
    componentDidMount : function(){  
        zingchart.render({  
            id : this.props.id,  
            width: (this.props.width || 600),  
            height: (this.props.height || 400),  
            data : this.props.data  
        });  
    },  
    //Used to check the values being passed in to avoid unnecessary changes.  
    shouldComponentUpdate : function(nextProps, nextState){  
        //Lazy object comparison  
        return !(JSON.stringify(nextProps.data) === JSON.stringify(this.props.data)) ;  
    },  
    componentWillUpdate : function(nextProps){  
        zingchart.exec(this.props.id, 'setdata', {  
            data : nextProps.data  
        })  
    }  
});  

Example usage :

var myConfig = {  
    "graphset": [{  
        "type" : "line",  
        "series":  [{  
            "values" : [0,4,2,2]  
        }]  
    }]  
};  
  
ReactDOM.render(<ZingChart id="myID" height="500" width="400" data={myConfig}/>, document.getElementById('container'));  

ZingChart.render()

Creates a <div> as a mount point for a ZingChart to be embedded within. We also use the prop id to set a unique ID value the ZingChart library needs.

ZingChart.componentDidMount()

componentDidMount() is a React method that is called after the render method is evaluated and the component is placed into the DOM. Once the <div> is mounted to the DOM, we instantiate ZingChart by calling the ZingChart's render function, just like we would without React.

ZingChart.shouldComponentUpdate()

shouldComponentUpdate() is another React method that determines if a component should re-render or not. If this method returns true, execution continues into the componentWillUpdate() method. If false, React stops evaluation and does not update the component.

Here we check to see if the data passed in through the data property has changed by performing a lazy string comparison. It is “lazy” since this will not evaluate an object's differences completely, but will suffice for this article.

For more detail on the comparison string, please see: http://stackoverflow.com/questions/15376185/is-it-fine-to-use-json-stringify-for-deep-comparisons-and-cloning

ZingChart.componentWillUpdate()

If the previous method shouldComponentUpdate() evaluated our data props to have different data (and the method returned true), then we re-render the chart. This is done by utilizing the ZingChart API method setdata() to change out the chart's dataset.

More information about the React lifecycle and when functions/events are called: http://javascript.tutorialhorizon.com/2014/09/13/execution-sequence-of-a-react-components-lifecycle-methods/

Try it:

See the Pen EyQOoy by ZingChart (@zingchart) on CodePen.

In the example above, we render a <ZingChart/> element to a container, passing a local variable to React's render method and evaluating it with the binding syntax { }. This isn't too exciting, as we have no way of updating our chart's data outside of React.

We added in the methods shouldComponentUpdate() and componentWillUpdate() methods, but are not utilizing them as of yet. Building on top of this component will make our <ZingChart/> component react to the data.

Part 2 - Making Components React to Each Other

reaction for reactjs
In order to communicate to our React component, we will need to come up with a hierarchy to manage our data. We will create a new component called <DataStore/> to handle our data and push the changes down to each <ZingChart/> component.

var DataStore = React.createClass({  
    getInitialState : function(){  
        return {  
             chart1val : []  
        }  
    },  
    render : function(){  
        return (  
            <div>  
                <ZingChart id="chart1" height="300" width="600" data={this.state.chart1val} />  
            </div>  
        );  
    },  
    componentDidMount : function(){  
        setInterval(this.changeData, 1000);  
    },  
    //Simulates a change of data.  
    changeData : function(){  
        this.setState({  
            chart1val : simulateLiveData()  
        });  
    }  
});  

Our <DataStore/> component provides a simple interface to handle our data. We created a separate state variable (chart1val) for the line chart we want to display. Inside of our componentDidMount() method, we utilize setInterval()to call a helper function changeData()every 1 second.

This helper function sets the state of our <DataStore/>  by polling dynamic data. React does all of the heavy lifting for us, pushing the new data down to each <ZingChart/> component.

For completeness, here is our simulateLiveData() function

function simulateLiveData(){  
    var data = [];  
  
    for(var j=0; j < 2; j++){  
        var series = {"values" : []};  
        for(var i = 0; i < 20; i++){  
            series['values'].push( Math.floor(Math.random() * 100));  
        }  
        data.push(series);  
    }  
    return {  
        "graphset" : [{  
            "type" : "line",  
            "series" : data  
        }]  
    };  
}  

This function simply creates a new ZingChart data object to be passed to the setdata() method.

For the purposes of this article, simulateLiveData() is a simple random generator. In a real application, you could replace this function with one that connects to a live data feed using an Ajax style call and then formats received data for the chart.

Try it here:

See the Pen React - ZingChart Example -2 by ZingChart (@zingchart) on CodePen.

Part 3 - Encapsulation and Reusability

reusability for different chart types
At this point, what we built is useful, but extremely rigid. We are relying on a single external function simulateLiveData() to handle the data formatting and chart configuration.

If we had many different endpoints for data to be displayed on different chart types (bar, line, pie...), our external method would get very lengthy and verbose. However, the good news is: we can do better!

Utilizing React, we can abstract each ZingChart component into separate chart components. Let's say my application needed line, bar, pie, and scatter charts to all be the same style. We can create components for each of these, wrapping the ZingChart component inside each. How it works:

var PieChart = React.createClass({  
    render : function(){  
        var obj = {  
            "graphset": [  
                {  
                    "type": "pie",  
                    "background-color" : "white",  
                    "legend" : {  
                        "alpha" : 0  
                    },  
                    "plot" :{  
                        "legend-marker":{  
                            "type" : "circle",  
                            "border-width" : 2,  
                            "border-color" : "white"  
                        },  
                        "rules":[  
                            {"rule":"%p == 0","background-color":"#7ABF30 #5F9427"},  
                            {"rule":"%p == 1","background-color":"#07BCDE #06A6C2"},  
                            {"rule":"%p == 2","background-color":"#ed4e4e #bb4747"},  
                            {"rule":"%p == 3","background-color":"#FFC107 #DAA506"},  
                            {"rule":"%p == 4","background-color":"#ea794d #B96746"}  
                        ]  
                    },  
                    "series": this.props.values  
                }  
            ]  
        };  
        return (  
            <ZingChart id={this.props.id} height={this.props.height} width={this.props.width} data={obj}/>  
        );  
    }  
});  

Usage
<PieChart id="mychart2" height="300" width="600" values={myValues} />

In this snippet, we created a new type of component called, appropriately, PieChart. The purpose of this component is to hold ZingChart configuration information to define a standard pie chart.

Instead of modifying the entire zingchart config object every single time our data values change, we can simply encapsulate the appropriate styling config within another component, and compose a <ZingChart />  component as an end result. This is accomplished by:

  • Setting the Pie’s props to accept values

  • Inserting the values directly into the series property inside the Pie’s config object

Naturally, we would have to change our DataStore component to handle our PieChart component and to format the data appropriately for a pie chart. Introducing a new helper function simulateLivePieData() updates values for the pie chart.

var DataStore = React.createClass({  
    getInitialState : function(){  
        return {  
             chart1val : [],  
             chart2val : []  
        }  
    },  
    render : function(){  
        return (  
            <div>  
                <ZingChart id="chart1" height="300" width="600" data={this.state.chart1val} />  
                <PieChart id="chart2" height="300" width="600" data={this.state.chart2val} />  
            </div>  
        );  
    },  
    componentDidMount : function(){  
        setInterval(this.changeData, 1000);  
    },  
    //Simulates a change of data.  
    changeData : function(){  
        this.setState({  
            chart1val : simulateLiveData(),  
            chart2val : simulateLivePieData()  
        });  
    }  
});  
function simulateLivePieData(){  
    var pieValues = [];  
  
    for(var i = 0; i < 5; i++){  
        pieValues.push({"values" : [Math.floor(Math.random() * 100)] })  
    }  
  
    return pieValues;  
}  

Try it here:

See the Pen VjQVxA by ZingChart (@zingchart) on CodePen.

Notice that we simply extended our existing <ZingChart/> component and composed a new component <PieChart/> with it. Both components are still available to be used and can be used at the same time as well.

To add in a variety of other chart types, we continue this pattern. Make new appropriately named components and be sure to employ the correct ZingChart JSON syntax within them to make the desired type of chart.

See the Pen React - ZingChart Example 5 by ZingChart (@zingchart) on CodePen.

As an exercise, we have set up the data and chart components slightly differently than one another. Explore the helper data functions we have created and see how they differ– not in the type of data, but how it is sent to our React components. Some functions prepare the data sent to be formatted directly for ZingChart, and others are generic sets of data to be consumed.

Data endpoints differ greatly on the web. For most, we do not have access to modify and format to our liking. That is why we set up the data and chart components as described above. There is no right and wrong way to approach this, as long as there is a consistent pattern.

ZingChart + React = Potential

This article was meant to provide a better understanding of how ZingChart and React can work together. Even though React is the new kid on the JavaScript library block, it holds a ton of potential to cleanly organize front end code.

The patterns presented here are not dogmatic, and we encourage you to modify them to your needs. Let us know if you have any suggestions in the comments below. Also, be sure to check out our updated post on ZingChart-React components!

comments powered by Disqus