Introduction
When most people think MVC, they typically describe the Model and the Controller in detail and then finish up the discussion with "then we have the View," or at least that is how most of my conversations have gone. I was first introduced to ReactJS at Fluent 2014 and was luckily enough to meet the some of the Facebook Engineering team during a networking event. React does challenge conventional wisdom and at a first glance some of the concepts may seem a bit crazy, but as their documentation suggests, if you give it five minutes those crazy ideas have brought thousands of successful components to Facebook and Instagram’s stack. ReactJS aims to solve one problem, which is, "How do you build large applications while accommodating the fact the data will change over time?" It is easy to understand why Facebook would aim to solve this problem. Give it Five!
ReactJS and Wijmo5
The nice thing about ReactJS is its definition, it truly separates the View from the rest of the application by abstracting any assumptions you may have had to make in the past. This is accomplished by using Virtual DOM. When we were developing Wijmo5, speed was scrutinized at every step of development and we observed that loading/updating/removing elements into and out of the DOM is a very expense operation, specifically with our FlexGrid, as users can load well over a million records into the grid and will observe no lag when scrolling due to Virtual Scrolling. That link will take you to our FlexGrid explorer page if you are not familiar with the control. This high level concept is very similar to what ReactJS wanted to accomplish. A library for building UI’s that abstracts the DOM away, giving a simpler programming interface as well as better performance. ReactJS allows you to build reusable components, thus encapsulating to make code reuse, testing, and separation of concerns very simple. ReactJS internally keeps track of changes to the View and calculates the minimum required changes to update the View based on the differences. ReactJS can also be used on the server-side with Node, where you can render pages on the server, for performance and SEO, but that is a discussion for another day. We will also table React Native for another discussion as well. So I introduced the Wijmo5 FlexGrid control earlier, so let’s use that control as our interop example. The FlexGrid is our most robust and most used control in large applications that deal with morphing data, so I think this is a good starting place. For those of us familiar with our controls, you will know that we support pure JavaScript, AngularJS, and Knockout. One of the nice features of ReactJS is the concept that it makes no assumptions about any other frameworks being used so it’s very easy to use AngularJS or Knockout. In this blog, I will just keep the focus on ReactJS and Wijmo5 so we will use plain old JavaScript here. It is important to note that our controls do not take advantage of the virtual DOM rendering that ReactJS provides, but it is important to show how you can integrate Wijmo5 controls within your ReactJS application.
How to get ReactJS and Wijmo5
To begin we need to load two external ReactJS libraries, they can be found on the ReactJS site, they even offer a nice Starter Pack ( direct link ) You will need the JSXTransformer and the React core. The JSXTransformer is the engine that takes the JSX code and converts it to JavaScript at rendering time. JSX is basically an extender of JavaScript and will look like XML. We talked about components earlier, you can think of components in ReactJS as functions that take in props and state and then renders HTML. If you want to read more, Facebooks documentation does a good job explaining it. JSX Docs You will also need Wijmo, you can download a free 30 day trial here
Example
To begin, we need to render a control host for our FlexGrid. Here is a link to the FlexGrid documentation if you want to familiarize yourself with the API [Documentation]. Note the comment line is required, I think it might have to do with some sort of bootstrapper that identifies JSX code blocks in the script tag. But here you can see that we are using ReactJS's createClass call.
//
/** @jsx React.DOM */
var FlexGrid = React.createClass({
render: function() {
return (
Hi
);
}});
FlexGrid
In the code above you can see we instantiate a new React class and assign it to the variable FlexGrid. This variable is how we will reference this control in our markup as we see in the code below. Basically, we are telling react to put the FlexGrid class into the grid_01 div.
React.render(, document.getElementById('grid_01'));
And we need to add some items to our mark-up. In the attached sample, I have included the same example in PureJS for your reference.
Now we need to introduce some ReactJS's Component Specs and Lifecycles. You can read about them here. I have already introduced the Render() method. Anytime you create a component class by invoking React.createClass(), you should provide a render method. Once you have done that you can optionally apply may others. The componentWillMount is invoked once, both on the client and the server, immediately before the initial render occurs. This is where we load our data into the collectionView. We assign the collectionView to var cv, so that "this.cv" is available throughout the lifecycle of the component. Since we defined our data array in our getInitialState, we can reference it using the this.state call. For those of us who are not familiar with the CollectionView, we are setting the Page size of the grid to six. You can change it or remove it if you want to show all the data.
componentWillMount: function()
{
this.cv = new wijmo.collections.CollectionView( this.state.grid\_01\_data );
this.cv.pageSize = 6;
},
The componentDidMount is invoked once, only on the client, immediately after the initial rendering occurs. At this point in the lifecycle, the component has a DOM representation which you can access via react.findDOMNode(this) If we want to integrate with other JavaScript frameworks, set timers using setTimeout or setInterval, or send AJAX requests, perform those operations in this method. In this case we are accessing a DOM reference and binding the itemSource of the FlexGrid to our collectionView that we introduced in the componentWillMount.
componentDidMount: function()
{
this.grid = new wijmo.grid.FlexGrid( this.getDOMNode(this.refs.grid_01), this.state.gridOpts);
this.grid.itemsSource = this.cv;
},
The componentWillUnmount is invoked immediately after the component's updates are flushed from the DOM, this method is not called after initial render. You can think of this as your cleanup method for cleaning anything you created in ComponentDidMount
componentWillUnmount: function() {
var div = React.findDOMNode(this);
var grid = wijmo.Control.getControl(div);
grid.dispose();
}
The code below is going to define the initial state of the control. This method is invoked once before the component is mounted via the componentWillMound method. The return values of this will be used as the initial value of this.state. You can note in the above examples that we were referencing this.state.gridOpts and this.state.gridData. Here is where we can define where they belong.
getInitialState: function() {
return {
gridOpts: {
selectionMode: wijmo.grid.SelectionMode.Cell,
showSort: false,
autoGenerateColumns: false,
columns: [
{header: "ID3", "binding":"country", "width":"*"},
{"header": "Country", "binding":"country", "width":"*"},
{"header": "Amount", "binding":"amount", "width":"*"}
],
itemFormatter: function(panel, r, c, cell){
if (wijmo.grid.CellType.Cell == panel.cellType &&
panel.columns[c].binding == 'amount') {
var cellData = panel.getCellData(r, c);
cell.style.color = getAmountColor(cellData);
}
},
},
grid\_01\_data: [
{"id":0, "country":"Greece", "amount": 2000},
{"id":1, "country":"USA", "amount": 100},
{"id":2, "country":"UK", "amount": 750},
{"id":3, "country":"Germany", "amount": 1500},
{"id":4, "country":"Japan", "amount": 2000},
{"id":5, "country":"Greece", "amount": 3000},
]
};
},
There is a lot of stuff going on here, so let me define it. I picked a few examples from our API to demo here. The first is the selectionMode which we set to cell. We also want to allow the user to sort, but we want to turn off that little triangle next to our Column header text via the showSort boolean. The next thing we want to do is to turn off the auto-generation of columns because we want to manually define our own columns. Thus, we create an array of column objects, assign header text, what data element from our collectionView that column will be bound to and finally the width of the column, which we set as a wildcard. The next thing I chose to show was the itemFormatter function. We can note that our itemFormatter calls a JavaScript function that applies the styling. This is very handy when it comes to code re-usability as we can have one data formatter function that we can apply to all of our components on the application, the way in which you call that formatter function can be different. Finally, we create our data model.
Conclusion
We introduced ReactJS and some of the advantages available to developers that they can leverage. Next we introduced the FlexGrid and talked a high level about the control and how we can use it in a ReactJS application. Thirdly, I showed you how to get ReactJS and Wijmo5 into your application. Finally, we worked through an example of how you can incorporate the Wijmo5 FlexGrid into the ReactJS JSX scaffolding.
Samples
Link to Github Source Plunkr // ]]>