First Look: Getting Started with Facebook’s ReactJS Library – Modern Web
Kirill Buga shares about his experience getting started with the ReactJS Library from Facebook.
Today, as JavaScript becomes more and more popular and the Front-end frameworks quantity grows dramatically. If you take a look at popular JavaScript frameworks such as Backbone.js, Angular.js, or Ember.js, you’ll notice that each one of them provides different abstraction level, implementation model and terminology. From this point of view ReactJS exceeded all of my expectations. It was created by developers from Facebook and is used in Facebook and Instagram – unbelievable, isn’t it? It will definitely change your perception of Front-End implementation.
Front-end coding is typically based on MVC pattern, where View is instance that renders text-templates into DOM-fragments. View displays data and reacts on user input and events. Data is stored in the Model. Change of Model leads to the change of View and this process is controlled by Controller. General model of this pattern is shown below.
What makes React then so different?
The thing is that View-part in React is replaced with so-called Component. It contains 2 instantiated objects: props
(it stores unchangeable parameters passed during object’s creation) and state
(it contains current state of the component and can be changed upon to some conditions). Well-known fact is that the most consuming operation in Front-end applications is call the DOM-tree. And React’s main distinction is that during View’s rendering it doesn’t construct physical DOM directly from templates. First of all it creates some temporal (virtual) DOM, compares it to real alongside with creation of Diffs, and only then makes call to DOM. Thus React closes access for the developer to DOM-tree and decides on its own when and why call to DOM should be made. “WAT?”, you probably ask. But keep it calm and don’t panic because first of all access to the real DOM is possible although it is not recommended. Secondly React’s implementation of virtual DOM is really awesome, so this technic allows you to manipulate View quickly.
Let’s go back to our Component which is the main React’s object. You can create complicated Web interfaces by combining Components. Each one of them implements render()
where the temporary DOM is created and this rendering can be hierarchic. This way the Components tree is created. Each block contains of its current state and is re-rendered after any change. Changes in parent’s component are also passed to children.
As an interim DOM is a part of Component, react.js provides useful XML-like extension as JSX. It allows building components’ tree as a set of XML nodes. Logic and markup are saved in the same file.
There is also JSX->JS converter (that can be found on the official web-site). You can call conversion from command-line (for example using build-systems such as Grunt and Gulp) or execute it on-site, by adding special script to your page. Second method isn’t recommended to use in production, because it may slow-down your application. Let’s take a look at some implementation – ToDo List. It’s popular example that was implemented with all possible frameworks.
Our application consists of 2 components – list of tasks and application itself.
Here is the list:
/** @jsx React.DOM */
var TodoList = React.createClass({
render: function() {
var createItem = function(itemText) {
return <li>{itemText}</li>;
};
return '<ul>{this.props.items.map(createItem)}</ul>';
}
});
Pay attention to the first line /** @jsx React.DOM */
.
It informs JSX-parser about JSX content inside that needs to be parsed. Component has only one method – render()
, that creates inside list of input parameters. In this case this.props data set that was passed during the creation. As you can see from example, you can manipulate Html-lines as JS-objects, since the output you’ll get will as shown below:
/** @jsx React.DOM */
var TodoList = React.createClass({displayName: 'TodoList',
render: function() {
var createItem = function(itemText) {
return React.DOM.li(null, itemText);
};
return React.DOM.ul(null, this.props.items.map(createItem));
}
});
It is completely valid JavaScript code. Each HTML tag will be replaced during parsing with React’s method. This is how interim DOM is created and what allows you to keep markup and code together. As for application component it looks far more interesting:
var TodoApp = React.createClass({
getInitialState: function() {
return {items: [], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.text]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return ('
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input onChange={this.onChange} value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
');
}
});
React.renderComponent('<TodoApp />', mountNode);
First of all, here you can see also other functions, some of them are standard others are custom. getInitialState(object) sets initial state of component. setState(object) changes the state and leads to render()
being called. In render()
of application we create task list with following code <TodoList items={this.state.items} />
. As argument the list of items was passed. For parent component this list is state, but for child – it is props. Change of state in parent’s component will lead to re-rendering of child nodes. All attributes in React use camelCase notation, and all parameters are in braces. Compiled JS will be as follows.
var TodoApp = React.createClass({displayName: 'TodoApp',
getInitialState: function() {
return {items: [], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.text]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return (
React.DOM.div(null,
React.DOM.h3(null, "TODO"),
TodoList( {items:this.state.items} ),
React.DOM.form( {onSubmit:this.handleSubmit},
React.DOM.input( {onChange:this.onChange, value:this.state.text} ),
React.DOM.button(null, 'Add #' + (this.state.items.length + 1))
)
)
);
}
});
React.renderComponent(TodoApp(null ), mountNode);
RenderComponent()
creates and renders Component. Functions onChange
and handleSubmit
are normal callbacks to users actions. One more distinction of react is usage of artificial events that do not bound to real DOM objects. React delegates events and attaches itself to root (you can read about this here).
Each component also passes few states in its lifecycle and special callback exists for each of them. As an example when component will mount calls to the method componentWillMount(). Afterwards it calls to the componentDidMount()
. There is a bunch of such callbacks but all of them follow this pattern – componentWill*
methods are called before state’s change, and componentDid*
methods – after. Here are some of examples:
getInitialState():
prepare initial state of the ComponentcomponentWillMount()
componentDidMount()
componentWillReceiveProps()
shouldComponentUpdate():
useful if you want to control when a render should be skipped.componentWillUpdate()
render()
componentDidUpdate()
componentWillUnmount()
All lifecycle of the component is as follows:
The main thing you must remember is that data is passed from parent to child and all events are passed from child to parent till they are handled.
If you want to have access to component after rendering you should set ref property for it
render: function(){
// Set a ref
return '<div>
<span ref="counter" class="count">{this.state.count}</span>
</div>';
}
Now you will be able to get it using this.refs.counter. To gain the access to physical DOM you should call this.refs.counter.getDOMNode().innerHTML
. Although it’s not recommended there can be cases when it is necessary.
React is powerful framework for Front-end application. And it’s no wonder that huge web-services use it for their goals. It implants another programming approach and restricts access to DOM but in return gives you an instrument for creating fast and easily extended web-applications.
You can find another articles on various topics from this author here.
- http://facebook.github.io/react/docs/why-react.html
- http://davidwalsh.name/event-delegate/
- http://facebook.github.io/react/
- http://code.tutsplus.com/tutorials/intro-to-the-react-framework–net-35660