Welcome dear reader! In this book, you'll find a set of blueprints that you can use to develop modern web apps with ReactJS.
This chapter will introduce you to ReactJS and cover how to work with a component-based architecture. You will learn all the important concepts in ReactJS, such as creating and mounting components, working with props and states, understanding the life cycle methods, and setting up a development workflow for efficient development.
In this chapter we will:
Introduce ReactJS
Explore the props and states
Learn all about the important life cycle methods
Walk through synthetic events and the virtual DOM
Learn the modern JavaScript developer's workflow
Composition
Create a basic scaffolding for all our apps
Even if you have previous experience with ReactJS, it's worth reading through this chapter, especially the scaffolding part, as we'll be using this scaffold for the majority of the blueprints in this book.
Let's begin!
To efficiently develop with ReactJS, it is vital to understand what it is and is not. ReactJS is not a framework. ReactJS describes itself as the V in the MVC (Model-View-Controller) design pattern. It's a view library that you can combine with frameworks such as AngularJS, Ember, and Meteor or even in conjunction with other popular JavaScript libraries, such as Knockout.
Many people use React on its own and combine it with a data flow pattern called Flux. The idea behind Flux is to establish unidirectional data flow, meaning that data should originate at a single point in your app and flow downwards. We'll look more closely into this pattern in Chapter 2, Creating a Web Shop.
In 2015, JavaScript got its first major upgrade in many years. The syntax is JavaScript 2015. You may know it as EcmaScript 6. The EcmaScript committee decided on a name change in mid-2015, and from now on, JavaScript is going to be updated yearly. Modern browsers are slowly implementing support for the new features.
Note
A note on the code you'll be seeing in this book. We will be using JavaScript 2015 throughout the book. Evergreen browsers such as Firefox, Chrome, and Microsoft Edge will implement the new functionality on their own timeline, which means that some browsers may support new features before others, while some features may not be implemented at all.
You will most likely find yourself in a situation where you'd like to take advantage of new language features without wanting to wait for it to be implemented. Backwards compatibility is also an issue because you don't want to leave your users behind.
The solution to both of these concerns is to use a transpiler to generate a baseline EcmaScript-5-compatible code, such as Traceur or Babel. Since Babel was partly built with ReactJS in mind, I suggest that you go with this one, and throughout the book, we'll be depending on Babel for our transpiling needs.
We'll be exploring the modern developer's workflow in this book by developing and iterating a scaffolding or a basic setup that we can use when starting new projects. When setting up and using this scaffolding, we'll rely heavily on the terminal, Node.js
and npm
. Don't worry if this is unfamiliar ground for you. We'll go slow.
ReactJS components have a built-in set of methods and properties that you'll come to rely on. Some of them are for debugging, such as displayName
and propTypes
; some for setting initial data, such as getInitialState
and getDefaultProps
; and finally, there are a number of methods dealing with the component life cycle, such as componentDidMount
, componentShouldUpdate
, and more.
Data within a component can come from the outside (props) or be instantiated from the inside (states).
For testability and immutability concerns, it's desirable to rely on data that is passed to components as much as possible rather than working with an internal state. However, there are lots of reasons why you'd want to use an internal state, so let's take a detailed look at props and states and when you want to use which.
Let's look at a simple component:
import React from 'react'; import { render } from 'react-dom'; const App = React.createClass({ render() { return ( <div>My first component</div> ); } }); render(<App />, document.querySelector('#app'));
When you execute this component, you will see the words My first component in your browser window.
The corresponding HTML file needs to look something like this:
<!DOCTYPE html> <body> <div id="app"></div> </body> <script type="text/javascript" src="app.js"></script>
This component defines a constant called app
, which creates a React component with the built-in createClass
method.
The rende
r method is the only required method in a ReactJS component. You can eschew all other methods, but this one. In render
, you can either write a combination of HTML and JavaScript called JSX or compose your HTML code using ReactJS elements.
Note
JavaScript doesn't understand JSX, so when you write JSX code, you need to convert it to JavaScript before executing it in the JavaScript environment. The easiest way to convert JSX is using the Babel transpiler because it will do this automatically.
Whichever way you decide to do it, the following JSX code will be transformed:
<div>My first component</div>
It will be transformed to this:
React.createElement("div", null, "My first component");
The createElement()
method accepts three parameters: the html
tag, a null
field, and the HTML code. The second field is actually an object with properties (or null
). We'll get back to this a little bit later.
Let's introduce the concept of properties and make this component a bit more interesting:
const App = React.createClass ({ render() { return ( <div>{this.props.greeting}</div> ); } }); render(<App greeting="Hello world!"/>, document.querySelector('#app'));
All component properties are available for use by accessing this.props
. Here, we set an initial message, Hello World!, and now, this is what you see when you execute the component:

Props cannot be modified and should be treated as immutable.
You can send as many properties as you want, and they are always available under this.props
.
If you have multiple properties that you want to send, just add them sequentially to the component call:
<App greeting="Hello world" message="Enjoy the day" />
You can set a component's initial props by calling getDefaultProps
. This can be helpful when you anticipate that a prop will be used, but it's not available until a later point in the component's life cycle:
getDefaultProps() { return { greeting: "" } }
If you call the component by adding a greeting, the component will simply show an empty page. If you don't have an initial prop, React will throw an error and complain that you're referencing a property that doesn't exist.
States are similar to props, but are meant for variables that are only available within the component. You can set a state in the same way as props:
setInitialState() { return { greeting: "Hello world!" } }
Also, you can call the variable with this.state
:
render() { return ( <div>{this.state.greeting}</div> ); }
Similar to props, if you try to use a nonexisting state variable, ReactJS will throw an error.
A state is primarily used when you make changes that only make sense within the component. Let's look at an example to understand this:
getInitialState: function () { return { random_number: 0 } }, componentDidMount(){ setInterval(()=>{ this.setState({ random_number: Math.random()*100 }); },1000) }, render() { return ( <div>{this.state.random_number}</div> ); }
Here, we set a random_number
variable to 0
. We access the built-in componentDidMount
method and start an interval that sets a new random number for this variable every second. In the render, we simply output the variable. Every time the state changes, ReactJS responds by re-rendering the output. Whenever you run setState
, ReactJS triggers a re-render of the component. It's worth taking care to limit the number of times you apply setState
, as you may run into performance issues if you're liberal with the use of them.
This is the only required method in a component. It should return a single child element, such as a JSX structure, but if you don't want to render anything, it can also return null
or false
to indicate that you don't want anything rendered:
render(){ return (<div>My component</div>); }
This object can be used to define static methods that can be called on the component:
import React from 'react'; const App = React.createClass ({ statics: { myMethod: (foo) => { return foo == "bar"; } }, render() { return null; } }); console.log(App.myMethod('bar')); // true
This object allows you to validate props being passed to your components. This is an optional tool to help you when developing your apps and will show up in your console log if the props you pass to a component do not match your specifications:
propTypes: { myOptionalObject: React.PropTypes.object, aRequiredString: React.PropTypes.string.isRequired, anOptionalNumber: React.PropTypes.number, aValueOfAnyKind: React.PropTypes.any, customProp: function(props, propName, componentName) { if (!/matchme/.test(props[propName])) { return new Error('Validation failed!'); } } }
The final example creates a custom validator, which you can use to validate even more complex data values.
Life cycle methods are a set of functions that you can override in your component. Initially, all but shouldComponentUpdate
(which defaults to true
) is empty.
This is one of the most common methods you'll employ in your apps. Here's where you place any functions you want to run directly after the component has been rendered for the first time.
You have access to the current contents of states and props in this method, but take care to never run setState
in here, as that will trigger an endless update loop.
It's worth noting that if you're making a server-side app, this component will not be called. In this case, you'll have to rely on componentWillMount
instead:
componentDidMount() { // Executed after the component is mounted }
This method will be executed before the component is rendered for the first time. You have access to the current component's state and props here, and unlike componentDidMount
, it's safe to run setState
here (ReactJS will understand that state changes in this method should be set immediately and not trigger a re-render).
This method is executed on both server-side and client-side apps:
componentWillMount() { // Executed before the component is mounted }
This method is invoked whenever the component receives new props or a change in state occurs.
By default, shouldComponentUpdate
returns a true
value. If you override it and return false
, the component will never be updated despite receiving updated props or a new state. This can be useful if you create a component that should only be updated if certain conditions are met or if it should never be updated at all. You can benefit from speed increases if you set this to false
when you have a component that should never be updated. However, you should take great care when using this method because careless use can lead to bugs that can be very hard to track down.
This method lets you compare the incoming props and can be used as an opportunity to react to a prop transition before the render method is called. Invoke this method with componentWillReceiveProps(object nextProps)
in order to access the incoming props with nextProps
.
It's worth noting that if you call setState
here, an additional re-render will not be triggered. It's not called for the initial render.
There's no analogous method to react to a pure state change, but you can use componentWillUpdate
if you need a way to react to state changes before they are rendered.
This method is not executed on the initial render:
componentWillReceiveProps(nextProps) { // you can compare nextProps with this.props // and optionally set a new state or execute functions // based on the new props }
This method is executed before the rendering, when the component receives new props or states but not on the initial render.
Invoke this method with componentWillUpdate(object nextProps, object nextState)
in order to access the incoming props and states with nextProps
and nextState
.
Since you can evaluate a new state in this method, calling setState
here will trigger an endless loop. This means that you cannot use setState
in this method. If you want to run setState
based on a prop change, use componentWillReceiveProps
instead:
componentWillUpdate (nextProps) { // you can compare nextProps with this.props // or nextState with this.state }
This method is executed whenever the component receives new props or states and the render method has been executed:
componentDidUpdate() { // Execute functions after the component has been updated }
Let's explore the differences between the regular DOM and the virtual DOM and what you need to consider when writing your code.
The Document Object Model (DOM) is a programming API for HTML documents. Whenever you ask a browser to render HTML, it parses what you have written and turns it into a DOM and then displays it in the browser. It is very forgiving, so you can write invalid HTML and still get the result you want without even knowing you made a mistake.
For instance, say, you write the following line of code and parse it with a web browser:
<p>I made a new paragraph! :)
After this, the DOM will show the following structure:

The closing </p>
tag is automatically inserted for you, and a DOM element for the <p>
tag has been created with all its associated properties.
ReactJS is not as forgiving. If you write the same HTML in your render
method, it will fail to render and throw an «Unterminated JSX contents»
error. This is because JSX requires a strict match between opening and closing tags. This is actually a good thing because it helps you with writing syntactically correct HTML.
The virtual DOM is basically a simpler implementation of the real DOM.
ReactJS doesn't work directly with the DOM. It uses a concept of virtual DOM, whereby it maintains a smaller and more simplified internal set of elements, and only pushes changes to the visible DOM when there has been a change of state in the set of elements. This enables you to switch out parts of your visible elements without the other elements being affected, and in short, this makes the process of DOM updates very efficient. The best part of this is that you get it all for free. You don't have to worry about it because ReactJS handles everything in the background.
It does, however, mean that you cannot look for changes in the DOM and make changes directly, like you would normally do with libraries, such as jQuery, or native JavaScript functions, such as getElementById()
.
Instead, you need to attach a reference named refs
to the elements you want to target. You can do this by adding ref="myReference"
to your element. The reference is now available through a call to React.findDOMNode(this.refs.myReference)
.
Whenever you call an event handler within ReactJS, they are passed an instance of SyntheticEvent instead of the native event handler. This has the same interface as the native event handler's, except it's cross-browser compatible so you can use it without worrying whether you need to make exceptions in your code for different browser implementations.
The events are triggered in a bubbling phase. This means that the event is first captured down to the deepest target and then propagated to outer elements.
Sometimes, you may find yourself wanting to capture the event immediately. In such cases, adding Capture
behind the event can achieve this. For instance, to capture onClick
immediately, use onClickCapture
and so on.
You can stop propagation by calling event.stopPropagation()
or event.preventDefault()
where appropriate.
Note
A complete list of the available event handlers is available at https://facebook.github.io/react/docs/events.html.
When we put all this together, we can extend the sample app with referenced elements and an event handler:
import React from 'react'; import {render} from 'react-dom'; const App = React.createClass ({ getInitialState() { return { greeting: "", message: "" } }, componentWillMount() { this.setState ({ greeting: this.props.greeting }); }, componentDidMount() { this.refs.input.focus(); }, handleClear: function (event) { this.refs.input.value=""; this.setState ({ message: "" }); }, handleChange: function (event) { this.setState ({ message: event.target.value }); }, render: function () { return ( <div> <h1>Refs and data binding</h1> <h2>{this.state.greeting}</h2> Type a message: <br/> <input type="text" ref="input" onChange={this.handleChange} /> <br/> Your message: {this.state.message} <br/> <input type="button" value="Clear" onClick={this.handleClear} /> </div> ); } }); render ( <App greeting="Let's bind some values" />, document.getElementById('#app') );
Let's start at the end. As we did earlier, we initialize our app by rendering a single ReactJS component called app with a single prop onto the element with the #app
ID.
Before the app mounts, we set initial values for our two state values: greeting
and message
. Before the app mounts, we set the state for greeting to be the same value as the greeting property passed to the app.
We then add the input box and a clear button as well as some text in our render
method and attach an onChange
handler and an onClick
handler to these. We also add ref
to the input box.
After the component has mounted, we locate the message box by its ref
parameter and tell the browser to focus on it.
Finally, we can go the event handlers. The onChange
handler is bound to handleChange
. It will activate on every key press and save a new message state, which is the current content of the input box. ReactJS will then re-render the content in the render
method. In the reconciliation process, it will note that the value in the input box is different from the last render, and it will make sure that this box is rendered with the updated value. At the same time, ReactJS will also populate the empty text element after Your message: with the state value.
The handleClear
method simply resets the message state and clears the input box using refs
.
This example is slightly contrived. It could be shortened quite a bit, and storing props as states is generally something you should avoid, unless you have a very good reason for doing so. In my experience, working with a local state is the single most bug-prone code you will encounter and the hardest code to write tests for.
Composition is the act of combining things together to make more complex things and then putting these things together to make even more complex things, and so on.
Knowing how to put together ReactJS components is vital when creating apps that go beyond Hello World. An app composed of many small parts is more manageable than a single large monolith app.
Composing apps is very simple with ReactJS. For instance, the Hello World app we just created can be imported into a new component with the following code:
const HelloWorld = require("./helloworld.jsx"); const HelloWorld = require("./helloworld.jsx");
In your new component, you can use the HelloWorld
variable like this:
render() { return <div> <HelloWorld /> </div> }
Every component you created can be imported and used in this manner, and this is one of the many compelling reasons for choosing ReactJS.
It's hard to overstate the importance of Node.js
and npm
in modern JavaScript development. These key pieces of technology are central to the development of JavaScript web apps, and we'll be relying on Node.js
and npm
for the applications that we will be developing in this book.
Node.js is available for Windows, Mac, and Linux, and is a breeze to install. We'll be using Node.js
and npm
for all of the examples in this book. We'll also be using EcmaScript 2015 and a transpiler to convert the code to a baseline JavaScript code that is compatible with older browsers.
If you haven't been using this workflow before, get ready to be excited because not only will it make you more productive, it will also open a world of developer goodness.
Let's begin.
The traditional method of developing for the Web had you manually adding scripts to your index.html
file. It usually consisted of a mix of frameworks or libraries topped off with your own code, which you then added sequentially so that it was loaded and executed in the correct order. There are a few drawbacks to this method of development. Version control becomes difficult because you have no good way of controlling whether newer versions of your external libraries are compatible with the rest of your code. As a consequence, many web apps ship with old JavaScript libraries. Organizing your scripts is another problem because you have to add and remove old versions manually when upgrading. File size is also problematic because many libraries ship with more bells and whistles than you need.
Wouldn't it be nice if we had tools that could keep your dependencies up to date, inform you when there are incompatibility issues, and remove code you don't use? The answer to all of this is yes, and fortunately, such utilities exist.
The only drawback is that you have to change the way you write your code. Instead of writing scripts that rely on global environment variables, you write modular code that is self-contained, and you always specify your dependencies up front. If you think that this doesn't sound like much of a drawback, you're right. In fact, it's a huge improvement because this makes it very easy to read and understand code and allows easy dependency injection when writing tests.
Two of the most popular tools for assembling modular code are Browserify and Webpack.
In the beginning, we'll focus on Browserify for the simple reason that it's very easy to work with and has excellent plugin support. We'll look at Webpack in Chapter 6, Advanced React. Both of these tools will analyze your application, figure out which modules you're using, and assemble a JavaScript file that contains everything you need to load the code in a browser.
In order for this to work, you need a base file, a starting point for your application. In our scaffold, we'll call this app.jsx
. This file will contain references to your modules and the components that it uses. When you create new components and connect them to app.jsx
or the children of app.jsx
, Browserify will add them to the bundle.
A number of tools exist to enhance the bundle generation with Browserify. For EcmaScript 2015 and newer JavaScript code, we'll use Babelify. It's a handy tool that in addition to converting JavaScript to EcmaScript 5 will also to convert React-specific code such as JSX. In other words, you don't have to use a separate JSX transformer in order to use JSX.
We'll also be using Browser-sync, which is a tool that auto reloads your code while you edit. This speeds up the development process immensely, and after using it for a while, you'll never want to go back to refreshing your app manually.
These are the steps we'll be taking to set up our development workflow:
Create an
npm
project.Install dependencies.
Create a server file.
Create a development directory.
Create our base
app.jsx
file.Run the server.
First of all, make sure that you have
npm
installed. If not, head over to https://nodejs.org/download/ and download the installer. The detailed explanation of the preceding steps is as follows:
Create a directory where you want the app to be sorted and open a terminal window and
cd
in this folder.Initialize your app by typing
npm init
followed by the Enter key. Give the project a name and answer the few questions that follow or just leave them empty.We're going to grab a few packages from
npm
to get started. Issuing the following command will get the packages and add the dependencies to your newly createdpackage.json
file:npm install â-save [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
Babel requires a configuration file called
.babelrc
. Add it to the following code:{ "presets": ["es2015","react"] }
Create a new text file with your favorite text editor, add the following code, and save it as
server.js
:var express = require("express"); var browserify = require('browserify-middleware'); var babelify = require("babelify"); var browserSync = require('browser-sync'); var app = express(); var port = process.env.PORT || 8080;
This segment sets up our app using express as our web server. It also initalizes
browserify
,babelify
, andbrowser-sync
. Finally, we set up our app to run on port8080
. The lineprocess.env.PORT || 8080
simply means that you can override the port by prefixing the server script withPORT 8085
to run on port8085
or any other port you'd like to use:browserify.settings ({ transform: [babelify.configure({ })], presets: ["es2015", "react"], extensions: ['.js', '.jsx'], grep: /\.jsx?$/ });
This sets up Browserify to transform all code with that of the file extension
.jsx
with Babelify. The stage0
configuration means that we want to use experimental code that has yet to be approved by the EcmaScript committee:// serve client code via browserify app.get('/bundle.js', browserify(__dirname+'/source/app.jsx'));
We want to reference our JavaScript bundle with
<script src="bundle.js"></script>
in ourindex.html
file. When the web server notices a call for this file, we tell the server to send the browserifiedapp.jsx
file in oursource
folder instead:// resources app.get(['*.png','*.jpg','*.css','*.map'], function (req, res) { res.sendFile(__dirname+"/public/"+req.path); });
With this configuration, we tell the web server to serve any of the listed files from
public.folder
:// all other requests will be routed to index.html app.get('*', function (req, res) { res.sendFile(__dirname+"/public/index.html"); });
This line instructs the web server to serve
index.html
if the user accesses the root path:// Run the server app.listen(port,function() { browserSync ({ proxy: 'localhost:' + port, files: ['source/**/*.{jsx}','public/**/*.{css}'], options: { ignored: 'node_modules' } }); });
Finally, this runs the web server with
browser-sync
, proxying your app at the port you choose. This means that if you specify port8080
as your port, your front-facing port will be a proxy port (usually3000
), which will access8080
on your behalf.We tell
browser-sync
to monitor all JSX files in oursource/
folder and our CSS files in ourpublic/
folder. Whenever these change,browser-sync
will update and refresh the page. We also tell it to ignore all the files in thenode_modules/
folder. This is generally wise to do because the folder will often contain thousands of files, and you don't want to waste time waiting for these files to be scanned.Next, create two a directories called
public
andsource
. Add the following three files:index.html
andapp.css
to your public folder andapp.jsx
to yoursource
folder.Write this in the
index.html
file:<!DOCTYPE html> <html> <head> <title>ReactJS Blueprints</title> <meta charset="utf-8"> <link rel="stylesheet" href="app.css" /> </head> <body> <div id="container"></div> <script src="bundle.js"></script> </body> </html>
Write this in the
app.css
file:body { background:#eee; padding:22px; } br { line-height: 2em; } h1 { font-size:24px; } h2 { font-size:18px; }
Write this in the
app.jsx
file:'use strict'; import React from 'react'; import { render } from 'react-dom'; const App = React.createClass({ render() { return ( <section> <h1>My scaffold</h1> <p>Hello world</p> </section> ); } }); render ( <App />, document.getElementById('container') );
Your file structure should now look like this:
Go the root of the app, type node server
, and then press Enter. This will start a node server and in a few seconds, browser-sync
will open a web browser with the location http://localhost:3000
. If you have any other web servers or processes running on port 3000
, browser-sync
will choose a different port. Take a look at the console output to make sure which port it has chosen.
You will see the contents of your render method from app.jsx
on the screen. In the background, Browserify has employed Babelify to convert your JSX and ES2015 code as well as your imported dependencies to a single bundle.js
file that is served on http://localhost:3000
. The app and CSS code will be refreshed every time you make a change in the code while this server is running, so I urge you to experiment with the code, implement a few life cycle methods, try working with states and props, and generally get a feel of working with ReactJS.
If this is your first time working with this kind of setup, I'd imagine you feel quite a rush surging through you right now. This setup is very empowering and fun to work with, and best of all, it's almost effortless to scaffold.
In this chapter, we looked at all the important concepts you will come to work with when you develop applications with ReactJS. We looked at the component specification, how to compose components, and life cycle methods before we went to look at how to set up and structure a ReactJS app. Finally, we went through the scaffolding that we'll be using for the blueprints in this book.
In the next chapter, we'll go through our first blueprint and create a web shop. We'll explore the concept of unidirectional data flow by taking advantage of the Flux pattern.