A primer for building web applications with React.
A primer for building Single-Page Applications with React.
This is a work in progress.
At the time of writing, the examples were written for
React 0.12.x. This guide will be updated with examples for
React 0.13
ES6 classessoon!
This primer makes use of several libraries, but it is by no means a "React the right way". It's just a introduction to how I am building my own React applications. The goal of this primer to help developers get familiar with React and dive right in. Maybe you will come up with approaches that work better for you and I hope that you share them with the community! Or if you're already well versed, help improve this document so others in the community can benefit. Sharing is caring!
This guide is dedicated to the engineers at Jellyvision, we are hiring so check us out. :D
~ Michael Chau (gh: @mikechau, twtr: @money_mikec)
My favorite part of React is what I loved about MooTools: to use it effectively you learn JavaScript, not a DSL: useful your whole career. - Ryan Florence (@ryanflorence)
#reactjsHaven’t been so excited about programming since learned Rails: http://facebook.github.io/react ! Kudos @floydophone & FB team! - Justin Gordon (@railsonmaui)
“It wasn’t my intention to use React for everything, but I found myself moving so quickly that I found I’d used it everywhere… had a blast” - Alan Hogan (@AlanHogan)
Remember to just give it 5 minutes.
The React community is super friendly!
Connect with other React developers at:
The React documentation is very good. Use this primer as a introduction and then read more about React by viewing the official documentation:
There's also a ton of resources at: Awesome React
React is a JavaScript library by Facebook, it describes itself as a javascript library for building user interfaces.
Developers often call it the V in MVC, or talk about the virtual DOM (not to be confused with the shadow DOM). I like React for its declarative style, lifecycle event hooks, and the fact that a React component describes its view at anytime. By breaking down the view into components, writing React starts to become very natural. React has been a pleasure to work with. You no longer need to understand the entire flow of the application at once, you can start at a component and work your way up or down.
This primer is meant to get you rapidly ready to start working with a React application. Its goal is not to teach and explain everything, but merely introduce concepts and help you form the right questions to ask and to have an idea of where to look for an answer. It is OK if you do not understand everything at first, just keep working at it by commiting the code you see to muscle memory and reading up on the documentation. Hopefully through reflection, and incubation, the concepts here will start to make sense.
Don't be afraid of React either. It may seem complex but is quite simple with a very small API of a dozen "essential" methods:
A React component encapsulates everything. It does not separate the view from the view logic, but rather merges the two together. Separating these does not really make sense when building a user interface: the view and its view logic are inevitably tightly coupled. Rather than jumping between a template file and some sort of view-controller it makes sense to keep them together. React components are usually small enough that this is not a big deal to have the two together, and if it does get to be too large you can break down your component into smaller components.
A key point from the React documentation:
Components are Just State Machines
React thinks of UIs as simple state machines. By thinking of a UI as being in various states and rendering those states, it's easy to keep your UI consistent.
In React, you simply update a component's state, and then render a new UI based on this new state. React takes care of updating the DOM for you in the most efficient way.
Read more: Interactivity and Dynamic UIs
JSX is pretty interesting. It basically allows using an HTML/XML-like syntax within JavaScript-based React components. Of course this wouldn't work if you tried to do that then serve it. Choosing to write your React component in JSX requires a transform process. This is typically handled through a build process or tool, like webpack.
var Button = React.createClass({ render: function() { return ( I am a button! Click me! ); } });React.render(, document.getElementById('content'));
Here you can see a React component has a
rendermethod, which returns markup. It's easy to see the shape of the output at a glance.
NOTE: As of version 0.13 React components can only ever return a single "root" element or sub-component.
For example, this is forbidden:
return (TestTest 2);
It has to be:
return ();TestTest 2
To render a React component in the body all you need to do is:
React.render(, document.getElementById('content'));
Simply call the render method, pass in the component, and the DOM node you want to render to.
NOTE: You should avoid rendering your React component directly into
document.body, as it can lead to subtle bugs.
When rendering a React component inside a DOM node, React wants complete ownership of the node. You should not add children to or remove children from a node in which React inserted a component.
So just create a
and then use
document.getElementById('content').
Like so:
// App.jsx React.render(, document.getElementById('content'));
Read more: JSX in Depth
React works with most common HTML elements, for example:
var Link = React.createClass({ render: function() { return ( Google ); } });React.render(, document.getElementById('content'));
You just made an
atag! It can now be called via .
Read more: React Tags and Attributes
React has a cross-compatibility layer for most specific browser events. Going back to our
Link:
var Link = React.createClass({ render: function() { return ( Google ); },handleClick: function(e) { e.preventDefault();
alert('You clicked me!');
} });
React.render(, document.getElementById('content'));
Now, I know what you're thinking. Inline events, isn't that bad? It looks like it's inline but it's really not. React will use event delegation behind the scenes. So now we have a very declarative way to associate events to DOM elements. Now there's no confusion as to what elements have what events and there is no hassle of managing binding hooks between DOM and javascript (e.g. ids or classes).
Here's a key point from the React documentation:
Event Handling and Synthetic Events
With React you simply pass your event handler as a camelCased prop similar to how you'd do it in normal HTML. React ensures that all events behave identically in IE8 and above by implementing a synthetic event system. That is, React knows how to bubble and capture events according to the spec, and the events passed to your event handler are guaranteed to be consistent with the W3C spec, regardless of which browser you're using.
If you'd like to use React on a touch device such as a phone or tablet, simply call
React.initializeTouchEvents(true);to enable touch event handling.
Under the Hood: Autobinding and Event Delegation
Autobinding: When creating callbacks in JavaScript, you usually need to explicitly bind a method to its instance such that the value of this is correct. With React, every method is automatically bound to its component instance. React caches the bound method such that it's extremely CPU and memory efficient. It's also less typing!
Event delegation: React doesn't actually attach event handlers to the nodes themselves. When React starts up, it starts listening for all events at the top level using a single event listener. When a component is mounted or unmounted, the event handlers are simply added or removed from an internal mapping. When an event occurs, React knows how to dispatch it using this mapping. When there are no event handlers left in the mapping, React's event handlers are simple no-ops. To learn more about why this is fast, see David Walsh's excellent blog post.
In the example, we defined a function, and simply passed the function to the
onClickproperty.
When the click event occurs, we receive back a synthetic event we can manipulate as usual e.g. call
#preventDefault()to stop the event's default action, or access the event's
#target.
Read more: React Events
To use the same event handler in multiple bindings and contexts, you may want to attach custom data to DOM nodes as you'd do in native javascript:
var Link = React.createClass({ render: function() { return ( ); },handleClick: function(e) { e.preventDefault();
alert('You clicked ' + e.target.getAttribute('data-link'));
} });
React.render(, document.getElementById('content'));
That is unnecessary in React, you can use
Function#bindand customize the handler itself via partial application:
var Link = React.createClass({ render: function() { return ( ); },handleClick: function(linkName, e) { e.preventDefault();
alert('You clicked ' + linkName);
} });
React.render(, document.getElementById('content'));
According to Javascript Is Sexy:
Partial function application is the use of a function (that accept one or more arguments) that returns a new function with some of the arguments already set. The function that is returned has access to the stored arguments and variables of the outer function. This sounds way more complex than it actually is, so let’s code. ...
An explanation of
.bind(this, ...)vs
.bind(null, ...)by
Morhauson
#reactjs:
React autobinds methods in the object you pass to
React.createClass()to the component instance, so usingthis.handleClick.bind(null, 'test')will ensure that behavior is not messed with...
pass null instead, unless you're not using
React.createClass()butclass extends React.Component, in which case methods are not auto bound
thiscan be passed to preserve the current context, or we can pass
nullif it is not necessary. In this case, since we are using
React.createClass, React will autobind the method for us so we can just pass
nulland whatever arguments we want applied.
Read more: Currying
Read more: Understand Javascript's "this" with Clarity and Master It
Read more: React Autobinding
Read more: bind(): React component methods may only be bound to the component instance
Read more: Partial application in JavaScript with
bind
Props are immutable parameters passed by a parent component to a child sub-component. A component can not alter its
#propsobject (and should not alter the props themselves), the only way for props to change is for a new render to be triggered, where the parent component passes new props to the child.
Props flow downwards, and in JSX they are provided as attributes of the component node:
// Parent Component var LikeList = React.createClass({ render: function() { return (
// Child Component var LikeListItem = React.createClass({ render: function() { return (
React.render(, document.getElementById('content'));
Here we have the Parent Component,
LikeList, render an unordered list, with one child, a
LikeListItem. To the
LikeListItemwe pass a
textproperty.
A component can access its props through
this.props,
textwould be accessed via
this.props.text. Here, the
textprop is simply accessed during rendering.
Read more: Transferring Props
getDefaultPropswill be called to get a default set of props, which will be overridden by the props eventually provided by a parent component. This is useful for optional props which have a sensible default value.
// Parent Component var LikeList = React.createClass({ render: function() { return (
// Child Component var LikeListItem = React.createClass({ getDefaultProps: function() { return { text: 'N/A' }; },
render: function() { return (
React.render(, document.getElementById('content'));
If no
textprop is passed, we give it a default value of
N/A. If defined,
getDefaultPropsmust return an object.
Read more: Default Prop Values
propTypesdocuments the props expected by a component and defines validators for generating warnings in the dev console.
It is recommended that you define
propTypesin any component that expects props. It is useful not only for validation during development but can be a way of documenting the component. It also makes it clear to others what the component expects.
A key point from the React
documentation:
Prop Validation
As your app grows it's helpful to ensure that your components are used correctly. We do this by allowing you to specify propTypes. React.PropTypes exports a range of validators that can be used to make sure the data you receive is valid. When an invalid value is provided for a prop, a warning will be shown in the JavaScript console. Note that for performance reasons propTypes is only checked in development mode. Here is an example documenting the different validators provided: ...
Example:
// Child Component var LikeListItem = React.createClass({ propTypes: { text: React.PropTypes.string },getDefaultProps: function() { return { text: 'N/A' }; },
render: function() { return (
Here we declare that the
textproperty must be a
string. By default, props are optional and should have a default value (provided through
getDefaultProps).
It is also possible to mandate that a prop be provided with the
isRequiredvalidator:
// Child Component var LikeListItem = React.createClass({ propTypes: { text: React.PropTypes.string.isRequired }, ...
getDefaultPropswas removed: since the property is required, there is no reason to provide a default value for it.
Read more: Prop Validation
React documentation introduction:
React supports a very special property that you can attach to any component that is output from render(). This special property allows you to refer to the corresponding backing instance of anything returned from render(). It is always guaranteed to be the proper instance, at any point in time.
Here is an example of how you can treat a
reflike an
id:
// Parent Component var LikeList = React.createClass({ componentDidMount: function() { console.log(this.refs.first.getDOMNode()); },render: function() { return (
// Child Component var LikeListItem = React.createClass({ render: function() { return (
React.render(, document.getElementById('content'));
NOTE: In React 0.13,
Component#getDOMNode()should be replaced by
React.findDOMNode(Component), the first one generates a warning in the console.
In this example, we can access the
refof
firstvia
this.refs.first. After
componentDidMounthas been called, the console output will be:
Read more: More About Refs
There may be situations where you want components to wrap provided components rather than generate those from props:
var Likes = React.createClass({ render: function() { return (); } });// Parent Component var LikesListWrapper = React.createClass({ render: function() { return (
// Child Component var LikeListItem = React.createClass({ render: function() { return (
React.render(, document.getElementById('content'));
Children are placed between a component's opening and ending tags, like regular HTML elements. The wrapper component can access those children via
this.props.children.
Read more: Children in JSX
Because
classis a reserved JavaScript keyword, to set the
classof an element you will need to use the
classNameproperty name instead.
render: function() { return ( I am a button with a class! ); }
Review: Tags and Attributes for more details on the supported
HTMLtags and
attributes.
Review: Events for the supported browser events.
When providing a boolean prop in JSX, passing the value is not necessary, as in HTML you can just add the key:
// SomeComponent.jsx var SomeComponent = React.createClass({ render: function() { return ( ); } });
AnotherComponent's
this.props.checkedwould resolve to
true.
As Pete Hunt noted, shared mutable state is the root of evil. Yet (mutable) state is often necessary. To that end, React components provide mutable state but not shared mutable state: only a component can alter its state, and a component can only alter its own state.
On a component's state change, a re-render of the tree will be automatically triggered.
State is useful for intermediate or self-contained component data, which should not or needs not be published externally. For instance a choice between liking something or not:
Do you like fish sticks?
Response: I ______ fishsticks.
I like them. I dislike them.
// logic.js $('#like').on('click', function(e) { e.preventDefault(); $('#response').text('like'); }); $('#dislike').on('click', function(e) { e.preventDefault(); $('#response').text('dislike'); });
The state of having liked or disliked fish sticks is fully internal, it does not come from an external source (a parent component) and is not published anywhere, thus in React:
var LikeComponent = React.createClass({ getInitialState: function() { return { response: '' }; },render: function() { return (
Do you like fish sticks?<br><br> Response: I {this.state.response || '_____'} fishsticks. <br><br> <a classname="btn btn-success" onclick="{this.handleLike}">I like it.</a> <a classname="btn btn-danger" onclick="{this.handleDislike}">I dislike it.</a> </div> );
},
handleLike: function(e) { e.preventDefault();
this.setState({ response: 'like' });
},
handleDislike: function(e) { e.preventDefault();
this.setState({ response: 'dislike' });
} });
React.render(, document.getElementById('content'));
getInitialStatehas the same purpose as
getDefaultProps, but because state is not shared rather than providing a default it provides the complete internal state of the component. State items can then be accessed through
this.state, much like props via
this.props.
State must not be altered directly.
It should generally be altered via
setState, which merges the provided object into the existing state then triggers a re-render: if the state is
{foo: 1, bar: 2},
this.setState({foo: 2})will result in a new state of
{foo: 2, bar: 2}.
NOTE: although sometimes tempting, setting up the initial state from props is generally an anti-pattern, it's usually better to compute from props on the fly.
For example:
getInitialState: function() { return { count: this.props.initialCount // this is fine because we make it clear that it is an initial value } }
Key Point:
Props in getInitialState Is an Anti-Pattern
Using props, passed down from parent, to generate state in getInitialState often leads to duplication of "source of truth", i.e. where the real data is. Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble.
Read more: Props in getInitialState Is an Anti-Pattern
Read more: State
React components have a somewhat involved lifecycle, but React provides a number of events/methods to hook in and act at various lifecycle points. The React documentation covers this section very well, so we will just quote it for convenience.
Read more: Component Specs and Lifecycle Events
componentWillMount()
Invoked once, both on the client and server, immediately before the initial rendering occurs. If you call
setStatewithin this method,render()will see the updated state and will be executed only once despite the state change.
Read more: componentWillMount
componentDidMount()
Invoked once, only on the client (not on the server), 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) [React 0.13+]orthis.getDOMNode() [React 0.12.x].If you want to integrate with other JavaScript frameworks, set timers using setTimeout or setInterval, or send AJAX requests, perform those operations in this method.
Read more: componentDidMount
componentWillReceiveProps(object nextProps)
Invoked when a component is receiving new props. This method is not called for the initial render.
Use this as an opportunity to react to a prop transition before
render()is called by updating the state usingthis.setState(). The old props can be accessed viathis.props. Callingthis.setState()within this function will not trigger an additional render.NOTE: There is no analogous method
componentWillReceiveState. An incoming prop transition may cause a state change, but the opposite is not true. If you need to perform operations in response to a state change, usecomponentWillUpdate.
Read more: componentWillReceiveProps
boolean shouldComponentUpdate(object nextProps, object nextState)
Invoked before rendering when new props or state are being received. This method is not called for the initial render or when
forceUpdateis used.Use this as an opportunity to
return falsewhen you're certain that the transition to the new props and state will not require a component update.If
shouldComponentUpdatereturnsfalse, thenrender()will be completely skipped until the next state change. (In addition,componentWillUpdateandcomponentDidUpdatewill not be called.)By default,
shouldComponentUpdatealwaysreturnstrueto prevent subtle bugs when state is mutated in place, but if you are careful to always treat state as immutable and to read only from props and state inrender()then you can overrideshouldComponentUpdatewith an implementation that compares the old props and state to their replacements.If performance is a bottleneck, especially with dozens or hundreds of components, use
shouldComponentUpdateto speed up your app.
componentWillUpdate(object nextProps, object nextState)
Invoked immediately before rendering when new props or state are being received. This method is not called for the initial render.
Use this as an opportunity to perform preparation before an update occurs.
Note: You cannot use
this.setState()in this method. If you need to update state in response to a prop change, usecomponentWillReceivePropsinstead.
Read more: componentWillUpdate
componentDidUpdate(object prevProps, object prevState)
Invoked immediately after the component's updates are flushed to the DOM. This method is not called for the initial render.
Use this as an opportunity to operate on the DOM when the component has been updated.
Read more: componentDidUpdate
componentWillUnmount()
Invoked immediately before a component is unmounted from the DOM.
Perform any necessary cleanup in this method, such as invalidating timers or cleaning up any DOM elements that were created in componentDidMount.
Read more: componentWillUnmount
React is great for rendering dynamic children. It's never been so easy.
Let's take the example:
var animalsListData = [ { id: 1, animal: 'tiger', name: 'Vee' }, { id: 2, animal: 'lion', name: 'Simba' }, { id: 3, animal: 'dog', name: 'Buck' }, { id: 4, animal: 'sealion', name: 'Seel' } ];var AnimalsList = React.createClass({ getInitialState: function() { return { animals: [] }; },
render: function() { if (!this.state.animals.length) { return (
No animals!); }return ( </pre>
React.render(, document.getElementById('content'));
Because
this.state.animalsis initially empty, the first render will display No animals!, as coded in the first part of the
rendermethod. We only render the list if there are animals in the list.
var animalsListData = [ { id: 1, animal: 'tiger', name: 'Vee' }, { id: 2, animal: 'lion', name: 'Simba' }, { id: 3, animal: 'dog', name: 'Buck' }, { id: 4, animal: 'sealion', name: 'Seel' } ];var AnimalsList = React.createClass({ getInitialState: function() { return { animals: [] }; },
componentDidMount: function() { this._fetchRemoteData(); },
render: function() { if (!this.state.animals.length) { return (
No animals!); }
Fetchreturn ( <div> <ul> { this.state.animals.map(function(animal, index) { return ( <li key="{index}"> {animal.name} the {animal.animal}! </li> ); }) } </ul> <a href="https://github.com/mikechau/react-primer-draft/blob/master/#reset" classname="btn btn-danger" onclick="{this.handleResetClick}"> Reset </a> </div> );
},
handleResetClick: function(e) { e.preventDefault(); this.setState({ animals: [] }); },
handleFetchClick: function(e) { e.preventDefault(); this._fetchRemoteData(); },
_fetchRemoteData: function() { setTimeout(function() { this.setState({ animals: animalsListData }); }.bind(this), 2000); } });
React.render(, document.getElementById('content'));
For the purpose of this example, we'll emulate data fetching with a
setTimeoutcall. In a real-world situation, you would use whatever AJAX library you prefer.
As soon as the component mounts, we "fetch" the remote data, which will update the internal state and re-render the component 2 seconds later. The fetching is done inline but could be split into a separate method (e.g.
_fetchRemoteData), and while we're fetching everything on mount, it could also be fetched only on a user action.
This example is a bit verbose, but hopefully it drives home how you can build your components. Do you see how intertwined your view and view logic end up being? Right from the
rendermethod, you can see exactly what it is going to output and what events are attached to what.
So let's summarize what is happening here:
stateis initialized,
this.state.animalsset to an empty array.
renderis called, we check if there is anything inside
this.state.animals, if there is nothing, we render the special case noting the lack of animals.
this._fetchRemoteData()
this._fetchRemoteData()completes,
this.setState(...)is called and a new
renderhappens! The update lifecycle events are also triggered.
To render dynamic children, simply
mapover your collection and return the components you want rendered by passing in the collection's item attributes as props.
NOTE: When mapping over an array, the result components must be given a
key.
Think of the
keyproperty as a unique identifier for the components being returned from
map.
Key point:
When React reconciles the keyed children, it will ensure that any child with key will be reordered (instead of clobbered) or destroyed (instead of reused).
So let's review:
render: function() { return (
As we map over
this.state.animals, we set the
keyprop to the current index in the array.
In general, it is recommended you pass the current index to
key, instead of generating a unique identifier or using one from the object.
funkiee from Hacker News explains why (Marko vs. React: Performance Benchmark):
Not necessarily addressing the speed portion, but if you're going to give a key to a repeated item in React, it is best to use the index instead of a unique identifier(if the overall DOM structure does not change much between renders) so that React does not destroy and recreate each item on tree change. ~ funkiee - Hacker News
As a follow up, you are probably thinking:
It re-creates items even when they have unique identifiers? Is that a bug? ~ myhf - Hacker News
To which, funkiee responds:
It's as intended. If the ID in a list of 100 changes, and that ID is the key, React is going to assume the tree is different during reconciliation. If you were to use an index, like 0, on pagination the key is still 0 and as such the DOM nodes will be reused. http://facebook.github.io/react/docs/reconciliation.html See #2 in the Trade-offs section. ~ funkiee - Hacker News
For your convenience, here are the trade-offs quoted from the React documentation:
Trade-offs
It is important to remember that the reconciliation algorithm is an implementation detail. React could re-render the whole app on every action; the end result would be the same. We are regularly refining the heuristics in order to make common use cases faster.
In the current implementation, you can express the fact that a sub-tree has been moved amongst its siblings, but you cannot tell that it has moved somewhere else. The algorithm will re-render that full sub-tree.
Because we rely on two heuristics, if the assumptions behind them are not met, performance will suffer.
- The algorithm will not try to match sub-trees of different components classes. If you see yourself alternating between two components classes with very similar output, you may want to make it the same class. In practice, we haven't found this to be an issue.
- If you don't provide stable keys (by using Math.random() for example), all the sub-trees are going to be re-rendered every single time. By giving the users the choice to choose the key, they have the ability to shoot themselves in the foot.
This will probably make more sense after reviewing the Reconciliation section in the React documentation.
NOTE: You only need to set the
keyfor the parent container component, it does not matter if it is a custom React component or an HTML container.
Example:
// CORRECT render: function() { return (
// NOT CORRECT render: function() { return (
keyjust needs to be set in the outermost component.
Read more: Recursing on Children
Read more: Reconciliation
Read more: Trade-offs
Read more: Marko vs. React: Performance Benchmark
Read more: React.js and Dynamic Children - Why the Keys are Important
Read more: React vs. Ember by Alex Matchneer
React is great for working with a tree structure like HTML. You can nest to your heart's content, it's encouraged. Remember: everything is a component. It's just like working in HTML, so it should start to come naturally to you.
Consider this
Appcomponent:
React.render(, document.getElementById('content'));
We render it to
#content.
Inside the
Appcomponent its
rendercould have an assortment of components. Maybe it looks like this:
// App.jsx ... render: function() { return (); } ...<maincontent> </maincontent>
// SubNavBar.jsx ... render: function() { return (
); } ...// MainContent.jsx ... render: function() { return (
<col md="{9}"> <dashboard></dashboard> </grid>
); } ...
Each component could keep going. Eventually you'd reach a point it actually returns the HTML, for example,
Gridmight actually just be an abstraction for:
// Grid.jsx render: function() { return ({this.props.children}); }
Mixins are a way of sharing reusable functionality between components.
Key point from React documentation:
Components are the best way to reuse code in React, but sometimes very different components may share some common functionality. These are sometimes called cross-cutting concerns. React provides mixins to solve this problem.
NOTE: The validity of mixins, is currently debated in the community. While you may continue to use them with
React.createClass, mixins are not currently available when using ES6 classes. The community seems to be leaning toward the idea of containers aka higher-order components or decorators (functions or components which manipulate or alter other components).
Mixin example:
var Mixin1 = { componentDidMount: function() { console.log('Mixin1, component did mount!'); } };var Mixin2 = { componentDidMount: function() { console.log('Mixin2, component did mount!'); } };
var Greeter = React.createClass({ mixins: [Mixin1, Mixin2],
componentDidMount: function() { console.log('Greeter, component did mount!'); },
render: function() { return (
Hi!); } });React.render(, document.getElementById('content'));
After
componentDidMount, the console should display:
"Mixin1, component did mount!" "Mixin2, component did mount!" "Greeter, component did mount!"
Mixins are a way of sharing functionality in lifecycle events between components. They can also be used to add custom methods to your React components.
Read more: Mixins
Read more: Higher-Order Components (HOC)
A simple performance boost you can get out of React is through the
PureRenderMixin.
Per the React documentation:
If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), you can use this mixin for a performance boost in some cases.
Under the hood, the mixin implements
shouldComponentUpdate, in which it compares the current props and state with the next ones and returns false if the equalities pass.Note: This only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only mix into components which have simple props and state, or use forceUpdate() when you know deep data structures have changed. Or, consider using immutable objects to facilitate fast comparisons of nested data. Furthermore, shouldComponentUpdate skips updates for the whole component subtree. Make sure all the children components are also "pure".
Let's check out an example:
var Greeter = React.createClass({ mixins: [React.addons.PureRenderMixin],getInitialState: function() { return { greeting: 'Hi' }; },
componentDidUpdate: function() { console.log('Component updated!'); },
render: function() { console.log('Component rendered!'); return (
Greeting: {this.state.greeting}
Say Hi<br> <a href="https://github.com/mikechau/react-primer-draft/blob/master/#" onclick="{this.handleGreetingClick.bind(null,"> Say Hey </a> </div> );
},
handleGreetingClick: function(greeting, e) { e.preventDefault();
console.log('click event', greeting); this.setState({ greeting: greeting });
} });
React.render(, document.getElementById('content'));
The initial state of
this.state.greeteris set to
Hi.
If we clicked the Say Hi action, the console would display:
"click event" "Hi"
No updates were applied because the previous state is
{greeting: 'Hi'}, and the new state is the exact same
{greeting: 'Hi'}. If the props and state haven't visibly changed since the last
render,
PureRenderMixinwill just skip the new one.
If we clicked Say Hey, the console would say the following instead:
"click event" "Hey" "Component rendered!" "Component updated!"
Read more: PureRenderMixin
The neat thing about React is you don't have to commit your whole application to using it. You can sprinkle it in and eventually... you'll want to write to everything in React. ;)
You can use third party libraries with React, even if they were not specifically written for React, some examples include jQuery UI, your favorite charting library or DataTables.
We will use DataTables as an example of how you could use it with React.
var accountingData = function() { var data = [];var random = (Math.floor(Math.random() * 10));
for (i = 0; i < random; i++) { data.push({ name: 'Transaction ' + (i + 1), amount: (Math.floor(Math.random() * 100)) }); }
return data; };
var AccountingTable = React.createClass({ getInitialState: function() { return { transactions: [] }; },
componentDidMount: function() { $(this.refs.table.getDOMNode()).DataTable(); },
componentWillUpdate: function() { var table = $(this.refs.table.getDOMNode()).DataTable(); table.destroy(); },
componentDidUpdate: function() { $(this.refs.table.getDOMNode()).DataTable(); },
componentWillUnmount: function() { var table = $(this.refs.table.getDOMNode()).DataTable(); table.destroy(); },
render: function() { return (
{ this.state.transactions.map(function(trans, index) { return ( ); }) }
Transaction Name Amount {trans.name} {trans.amount} <a href="https://github.com/mikechau/react-primer-draft/blob/master/#" classname="btn btn-default" onclick="{this.handleGetTransactionsClick}">Get Transactions</a> </div> );
},
handleGetTransactionsClick: function(e) { e.preventDefault();
this.setState({ transactions: accountingData() });
} });
React.render(, document.getElementById('content'));
This example is incredibly arbitrary. You would probably update the table via ajax instead, or write your own table component, or use something off the shelf for React like FixedDataTable from Facebook or Griddle, etc.
In this example, our initial state,
this.state.transactions, is an empty array.
After
componentDidMount, we initialize and render
DataTable.
Then on Get Transactions, we update the
statewith the data.
Before the component updates, we destroy
DataTable, and reinitialize it on
componentDidUpdate. When the component unmounts we will also destroy the
DataTableto clean up any associated event handler or resource.
If there are more interactions with the table, instead of asking React for the DOM node every time, we could store a reference in something like
this._dataTableRef.
You could also have a React component which doesn't render anything to the DOM (aside from a required component root) but uses its lifecycle events to trigger commands on a third party library to manipulate the DOM. This concept is what Ryan Florence calls a portal.
Read more: React.js Conf 2015 - Hype! (Portals) - Video.
Read more: Portals Example Repo
Read more: "Portals" in React.js
As you start to build out your React application, you may find yourself asking: how do I get this child component to update the state of my parent component?
You can simply pass down a callback function from the Parent Component to the Child Component.
For example:
var ShoppingList = React.createClass({ getInitialState: function() { return { items: [ { id: 1, name: 'Apple', qty: 2 }, { id: 2, name: 'Orange', qty: 3 }, { id: 3, name: 'Chicken', qty: 1 } ] }; },render: function() { return ( ); },
handleItemClick: function(name, e) { e.preventDefault(); console.log('click event', name); } });
var List = React.createClass({ propTypes: { items: React.PropTypes.array.isRequired, onClick: React.PropTypes.func.isRequired },
render: function() { return (
React.render(, document.getElementById('content'));
In this example, we have a
ShoppingListparent component, that renders a
Listchild component.
Let's walk through the process:
ShoppingListsets its initial state of
itemsto an array:
[ { id: 1, name: 'Apple', qty: 2 }, { id: 2, name: 'Orange', qty: 3 }, { id: 3, name: 'Chicken', qty: 1 } ]
It passes
this.state.itemsto the
Listcomponent, along with the callback function
#handleItemClick.
Listcomponent, expects the
propTypesof
items(array) and
onClick(function), both are required.
Listcreates dynamic children via map, which is binded. It returns
key. Inside of the
tag with an
onClickevent, where we pass the
this.props.onClickcallback function we were given from the parent. We also bind
this.props.onClickto get back the
item.name.
Upon clicking Apple, you should see in the console:
"click event" "Apple"
Then
#setStateis called, which will update
activeItemto whatever the name of the item that was clicked.
This example will show you how you could fetch data from inside your component. As your application grows and becomes more complex, you will probably want to use Flux.
In this example, we have an API that we can query to retrieve a collection of videos that we want to display. We want to be able to switch between videos, display its metadata (timestamp, title, etc) and show what video we are on and what the total videos are.
Note: For the sake of this example, we will use jQuery to help ease you into React. jQuery is absolutely not necessary, but for the convenience of making a AJAX request it will be used.
Here is a mockup of what we want to create:
+-----------------------------------------------------------+ | [App] | | | | +------------------------------------------------------+ | | | Title (Current Video Index / Total Videos) | | | | | | | |[HeaderView] | | | +------------------------------------------------------+ | | +------------------------------------------------------+ | | |[StageView] | | | | +--------------------------------+ | | | | | Video | | | | | | | | | | | Previous | | Next | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +--------------------------------+ | | | | +--------------------------------+ | | | | | Metadata | | | | | +--------------------------------+ | | | +------------------------------------------------------+ | +-----------------------------------------------------------+
Components have been marked with [brackets].
The code:
var App = React.createClass({ getInitialState: function(){ return { videoData: [], currentVideo: 0, totalVideos: 0 } },componentDidMount: function(){ this._retrieveVideos(); },
render: function(){ return(
); },_retrieveVideos: function(){ //Ajax $.getJSON( "http://jetclips.herokuapp.com/api/v1/videos/489159771140559", function( data ) { this.setState({videoData: data}); }.bind(this)); },
_updateIndex: function(n){ this.setState({currentVideo: this.state.currentVideo + n}); } });
var HeaderView = React.createClass({ propTypes: { title: React.PropTypes.string, currentVideo: React.PropTypes.number, totalVideos: React.PropTypes.number },
render: function() { return (
); } });{this.props.title} {this.props.currentVideo} / {this.props.totalVideos}
var StageView = React.createClass({ propTypes: { video: React.PropTypes.object.isRequired, onChange: React.PropTypes.func.isRequired },
componentDidMount: function(){ $("body").keydown(this._handleArrowKeys); },
componentWillUnmount: function() { $("body").off(this._handleArrowKeys); },
render: function() { return (
); },nextVideo: function(e){ e.preventDefault(); this.props.onChange(1); },
prevVideo: function(e){ e.preventDefault(); this.props.onChange(-1); },
_handleArrowKeys: function(e) { if (e.keyCode === 37) { this.prevVideo(e); };
if (e.keyCode === 39) { this.nextVideo(e); }
} });
React.render(, document.getElementById('content'));
You can see that [App] is the entry point, the AJAX request gets called, and then we pass down the relevant props down to [HeaderView] and [StageView].
If you commented out
#_retrieveVideosinside [App], you would see there wouldn't be anything there.
You can also see that a
#_updateIndexfunction gets passed down to [StageView] to manage the moving between videos.
Also if you look at [StageView], when the component mounts we attach a
#keydownevent listener to the body so we can move between videos when the left or right arrow key is pressed.
Remember: When attaching events on mount, you should clean them up on
componentWillUnmount.
Feel free to mess around with this example and experiment with things! One area of improvement is the logic for [App]'s
#_updateIndex. There should be guards to prevent one from going back past the first video and the last or perhaps it should loopback.
React has a handy developer debug tool, for Chrome, check it out: React Developer Tools.
Initially known as Harmony or ES6, ES2015 is an update to the ECMAScript standard.
This document will refer to the new upcoming standard for ECMAScript as ES6.
While ES6 browser support is still in progress, many developers are taking advantage of it today. They are doing so through the use of a transpiler like Babel. Babel will take your ES6 code and convert it into ES5, so developers can start taking advantage of ES6 while browsers work to implement the ES6 standard.
This section will cover some of the new syntax you may commonly see in React projects taking advantage of ES6.
It is recommended you review one of the following overviews (or maybe look at all of them) to get a better understanding about ES6's features.
Read more: ECMAScript 6 Overview
Read more: Using ECMAScript 6 today
Read more: You Don't Know JS: ES6 & Beyond
Read more: ES6 compatibility table
If you are unfamiliar with modules, it is a way of declaring dependencies. The idea is similar to
requirein Ruby or
importin Python.
Read more: ECMAScript 6 modules: the final syntax
Read more: Understanding Javascript Modules
Read more: Node.js modules - Review this if you are unfamiliar with node modules.
You may already be familiar with CommonJS modules, especially if you have done work with Node.js.
To refresh your memory, it looks like this:
var React = require('react');var MyComponent = React.createClass(...);
You can now instead do:
import React from 'react';
To import a specific function:
// ES6 import { Grid, Row, Column } from 'react-bootstrap';// CommonJS Equivalent var ReactBootstrap = require('react-bootstrap'); var Grid = ReactBootstrap.Grid; var Row = ReactBootstrap.Row; var Column = ReactBootstrap.Column;
To specify what you want to export by default, observe the following:
// MyReactComponent.jsx //ES6 export default MyReactComponent;// CommonJS Equivalent module.exports = MyReactComponent;
// Import the default import MyReactComponent from './MyReactComponent';
You can also export multiple things.
// MyReactComponent.jsx export SOME_CONST; export someFunction; export default MyReactComponent;// Import something specific import { SOME_CONST, someFunction } from './MyReactComponent';
varcan be replaced with either
letor
const. In most cases, you will probably want to use
const.
Read more: Let + Const
constis single-assignment. This means that it is read-only.
MDN explanation:
Summary
The const declaration creates a read-only named constant.
Description
This declaration creates a constant that can be global or local to the function in which it is declared. Constants are block-scoped. The value of a constant cannot change through re-assignment, and a constant cannot be re-declared. An initializer for a constant is required. A constant cannot share its name with a function or a variable in the same scope.
const test = "x";// error cant reassign a const test = "y";
const test = {key: 'value'}; // OK (object attributes are not protected) test.key2 = '1';
Read more: MDN - const
MDN explanation:
Summary
The let statement declares a block scope local variable, optionally initializing it to a value.
Description
let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.
Example from MDN:
function letTest() { let x = 31; if (true) { let x = 71; // different variable console.log(x); // 71 } console.log(x); // 31 }
Read more: MDN - let
The arrow function, or fat arrow works similar to how it does in Coffeescript.
According to MDN:
An arrow function expression (also known as fat arrow function) has a shorter syntax compared to function expressions and lexically binds the this value. Arrow functions are always anonymous.
Example:
const ListComponent = React.createClass({ propTypes: { items: React.PropTypes.array },getInitialState: function() { return { starredItemIndex: 0 } },
render: function() { return (
In the above example, you can see how we call the fat arrow within the map, instead of having to
#bind(this), so we have access to get
state#starredItemIndex.
this.props.items.map(function(item, index) { ... }).bind(this)
or doing something like:
const self = this; return (
Read more:
Arrow functions and their scope
ES6 brings some additional conveniences. es6features by lukehoban sums it up nicely:
Object literals are extended to support setting the prototype at construction, shorthand for foo: foo assignments, defining methods, making super calls, and computing property names with expressions. Together, these also bring object literals and class declarations closer together, and let object-based design benefit from some of the same conveniences.
Example from es6features:
var obj = { // __proto__ __proto__: theProtoObj, // Shorthand for ‘handler: handler’ handler, // Methods toString() { // Super calls return "d " + super.toString(); }, // Computed (dynamic) property names [ 'prop_' + (() => 42)() ]: 42 };
With ES6 React components, you will most likely see the function shorthand being used.
Example:
const ListComponent = React.createClass({ render() { return (
Instead of doing
render: function() { ... }, the shorthand
render() { ... }can be used.
Read more:
es6features - Enhanced Object Literals
Object-Based JavaScript in ES6
SuperAgent is a small progressive client-side HTTP request library, and Node.js module with the same API, sporting many high-level HTTP client features.
Bluebird is a fully featured promise library with a focus on innovative features and performance.
lodash is a JavaScript utility library delivering consistency, modularity, performance & extras.
normalizr normalizes deeply nested JSON API responses according to a schema for Flux applications.
Copyright (c) 2015 Michael Chau.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".