The React Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic.

I find this approach gives a well-rounded overview. This book does not try to cover everything under the sun related to React, but it should give you the basic building blocks to get out there and become a great React developer. If you think some specific topic should be included, tell me. You can reach me on Twitter @flaviocopes.

I hope the contents of this book will help you achieve what you want: learn the basics of React.

You can get this ebook in PDF, ePub and Mobi format at reacthandbook.com

Book Index

Table of Contents

An introduction to React

How to use create-react-app

SECTION 1: MODERN JAVASCRIPT CORE CONCEPTS YOU NEED TO KNOW TO USE REACT

SECTION 2: REACT CONCEPTS

SECTION 3: IN-DEPTH REACT

SECTION 4: PRACTICAL EXAMPLES

SECTION 5: STYLING

SECTION 6: TOOLING

SECTION 7: TESTING

SECTION 8: THE REACT ECOSYSTEM

Wrapping up

An introduction to the React view library

What is React?

React is a JavaScript library that aims to simplify development of visual interfaces.

Developed at Facebook and released to the world in 2013, it drives some of the most widely used apps, powering Facebook and Instagram among countless other applications.

Its primary goal is to make it easy to reason about an interface and its state at any point in time, by dividing the UI into a collection of components.

Why is React so popular?

React has taken the frontend web development world by storm. Why?

Less complex than the other alternatives

At the time when React was announced, Ember.js and Angular 1.x were the predominant choices as a framework. Both these imposed so many conventions on the code that porting an existing app was not convenient at all.

React made a choice to be very easy to integrate into an existing project, because that’s how they had to do it at Facebook in order to introduce it to the existing codebase. Also, those 2 frameworks brought too much to the table, while React only chose to implement the View layer instead of the full MVC stack.

Perfect timing

At the time, Angular 2.x was announced by Google, along with the backwards incompatibility and major changes it was going to bring. Moving from Angular 1 to 2 was like moving to a different framework, so this, along with execution speed improvements that React promised, made it something developers were eager to try.

Backed by Facebook

Being backed by Facebook is, of course, going to benefit a project if it turns out to be successful.

Facebook currently has a strong interest in React, sees the value of it being Open Source, and this is a huge plus for all the developers using it in their own projects.

Is React simple to learn?

Even though I said that React is simpler than alternative frameworks, diving into React is still complicated, but mostly because of the corollary technologies that can be integrated with React, like Redux and GraphQL.

React in itself has a very small API, and you basically need to understand 4 concepts to get started:

Components

JSX

State

Props

All these (and more) are explained in this handbook.

How to install React on your development computer

How do you install React?

React is a library, so saying install might sound a bit weird. Maybe setup is a better word, but you get the concept.

There are various ways to setup React so that it can be used on your app or site.

Load React directly in the web page

The simplest one is to add the React JavaScript file into the page directly. This is best when your React app will interact with the elements present on a single page, and not actually controls the whole navigation aspect.

In this case, you add 2 script tags to the end of the body tag:

<html> ... <body> ... <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.development.js" crossorigin ></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js" crossorigin ></script> </body> </html>

Please change the version number to the latest version of React available.

Here we loaded both React and React DOM. Why 2 libraries? Because React is 100% independent from the browser and can be used outside it (for example on Mobile devices with React Native). Hence the need for React DOM, to add the wrappers for the browser.

After those tags you can load your JavaScript files that use React, or even inline JavaScript in a script tag:

<script src="app.js"></script> <!-- or --> <script> //my app </script>

To use JSX you need an extra step: load Babel

<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

and load your scripts with the special text/babel MIME type:

<script src="app.js" type="text/babel"><;/script>

Now you can add JSX in your app.js file:

const Button = () => { return <button>Click me!</button> } ReactDOM.render(<Button />, document.getElementById('root'))

Check out this simple Glitch example: https://glitch.com/edit/#!/react-example-inline-jsx?path=script.js

Starting in this way with script tags is good for building prototypes and enables a quick start without having to set up a complex workflow.

How to use create-react-app

create-react-app is a project aimed at getting you up to speed with React in no time, and any React app that needs to outgrow a single page will find that create-react-app meets that need.

You start by using npx , which is an easy way to download and execute Node.js commands without installing them. npx comes with npm (since version 5.2) and if you don't have npm installed already, do it now from https://nodejs.org (npm is installed with Node).

If you are unsure which version of npm you have, run npm -v to check if you need to update.

Tip: check out my OSX terminal tutorial if you’re unfamiliar with using the terminal, applies to Linux as well — I’m sorry but I don’t have a tutorial for Windows at the moment, but Google is your friend.

When you run npx create-react-app <app-name> , npx is going to download the most recent create-react-app release, run it, and then remove it from your system. This is great because you will never have an outdated version on your system, and every time you run it, you're getting the latest and greatest code available.

Let’s start then:

npx create-react-app todolist

This is when it finished running:

create-react-app created a files structure in the folder you told ( todolist in this case), and initialized a Git repository.

It also added a few commands in the package.json file, so you can immediately start the app by going into the folder and run npm start .

In addition to npm start , create-react-app added a few other commands:

npm run build : to build the React application files in the build folder, ready to be deployed to a server

: to build the React application files in the folder, ready to be deployed to a server npm test : to run the testing suite using Jest

: to run the testing suite using Jest npm eject : to eject from create-react-app

Ejecting is the act of deciding that create-react-app has done enough for you, but you want to do more than what it allows.

Since create-react-app is a set of common denominator conventions and a limited amount of options, it's probable that at some point your needs will demand something unique that outgrows the capabilities of create-react-app .

When you eject, you lose the ability of automatic updates but you gain more flexibility in the Babel and Webpack configuration.

When you eject the action is irreversible. You will get 2 new folders in your application directory, config and scripts . Those contain the configurations - and now you can start editing them.

If you already have a React app installed using an older version of React, first check the version by adding console.log(React.version) in your app, then you can update by running yarn add react@16.7 , and yarn will prompt you to update (choose the latest version available). Repeat for yarn add react-dom@16.7 (change "16.7" with whatever is the newest version of React at the moment)

CodeSandbox

An easy way to have the create-react-app structure, without installing it, is to go to https://codesandbox.io/s and choose "React".

CodeSandbox is a great way to start a React project without having to install it locally.

Codepen

Another great solution is Codepen.

You can use this Codepen starter project which already comes pre-configured with React, with support for Hooks: https://codepen.io/flaviocopes/pen/VqeaxB

Codepen “pens” are great for quick projects with one JavaScript file, while “projects” are great for projects with multiple files, like the ones we’ll use the most when building React apps.

One thing to note is that in Codepen, due to how it works internally, you don’t use the regular ES Modules import syntax, but rather to import for example useState , you use

const { useState } = React

and not

import { useState } from 'react'

SECTION 1: MODERN JAVASCRIPT CORE CONCEPTS YOU NEED TO KNOW TO USE REACT

Find out if you have to learn something before diving into learning React

If you are willing to learn React, you first need to have a few things under your belt. There are some prerequisite technologies you have to be familiar with, in particular related to some of the more recent JavaScript features you’ll use over and over in React.

Sometimes people think one particular feature is provided by React, but instead it’s just modern JavaScript syntax.

There is no point in being an expert in those topics right away, but the more you dive into React, the more you’ll need to master those.

I will mention a list of things to get you up to speed quickly.

Variables

A variable is a literal assigned to an identifier, so you can reference and use it later in the program.

Variables in JavaScript do not have any type attached. Once you assign a specific literal type to a variable, you can later reassign the variable to host any other type, without type errors or any issue.

This is why JavaScript is sometimes referred to as “untyped”.

A variable must be declared before you can use it. There are 3 ways to do this, using var , let or const , and those 3 ways differ in how you can interact with the variable later on.

Using var

Until ES2015, var was the only construct available for defining variables.

var a = 0

If you forget to add var you will be assigning a value to an undeclared variable, and the results might vary.

In modern environments, with strict mode enabled, you will get an error. In older environments (or with strict mode disabled) this will simply initialize the variable and assign it to the global object.

If you don’t initialize the variable when you declare it, it will have the undefined value until you assign a value to it.

var a //typeof a === 'undefined'

You can redeclare the variable many times, overriding it:

var a = 1 var a = 2

You can also declare multiple variables at once in the same statement:

var a = 1, b = 2jsx

The scope is the portion of code where the variable is visible.

A variable initialized with var outside of any function is assigned to the global object, has a global scope and is visible everywhere. A variable initialized with var inside a function is assigned to that function, it's local and is visible only inside it, just like a function parameter.

Any variable defined in a function with the same name as a global variable takes precedence over the global variable, shadowing it.

It’s important to understand that a block (identified by a pair of curly braces) does not define a new scope. A new scope is only created when a function is created, because var does not have block scope, but function scope.

Inside a function, any variable defined in it is visible throughout all the function code, even if the variable is declared at the end of the function it can still be referenced in the beginning, because JavaScript before executing the code actually moves all variables on top (something that is called hoisting). To avoid confusion, always declare variables at the beginning of a function.

Using let

let is a new feature introduced in ES2015 and it's essentially a block scoped version of var . Its scope is limited to the block, statement or expression where it's defined, and all the contained inner blocks.

Modern JavaScript developers might choose to only use let and completely discard the use of var .

If let seems an obscure term, just read let color = 'red' as let the color be red and it all makes much more sense

Defining let outside of any function - contrary to var - does not create a global variable.

Using const

Variables declared with var or let can be changed later on in the program, and reassigned. Once a const is initialized, its value can never be changed again, and it can't be reassigned to a different value.

const a = 'test'

We can’t assign a different literal to the a const. We can however mutate a if it's an object that provides methods that mutate its contents.

const does not provide immutability, just makes sure that the reference can't be changed.

const has block scope, same as let .

Modern JavaScript developers might choose to always use const for variables that don't need to be reassigned later in the program.

Why? Because we should always use the simplest construct available to avoid making errors down the road.

Arrow functions

Arrow functions were introduced in ES6 / ECMAScript 2015, and since their introduction they changed forever how JavaScript code looks (and works).

In my opinion this change was so welcoming that you now rarely see the usage of the function keyword in modern codebases.

Visually, it’s a simple and welcome change, which allows you to write functions with a shorter syntax, from:

const myFunction = function() { //... }

to

const myFunction = () => { //... }

If the function body contains just a single statement, you can omit the brackets and write all on a single line:

const myFunction = () => doSomething()

Parameters are passed in the parentheses:

const myFunction = (param1, param2) => doSomething(param1, param2)

If you have one (and just one) parameter, you could omit the parentheses completely:

const myFunction = param => doSomething(param)

Thanks to this short syntax, arrow functions encourage the use of small functions.

Implicit return

Arrow functions allow you to have an implicit return: values are returned without having to use the return keyword.

It works when there is a one-line statement in the function body:

const myFunction = () => 'test' myFunction() //'test'

Another example, when returning an object, remember to wrap the curly brackets in parentheses to avoid it being considered the wrapping function body brackets:

const myFunction = () => ({ value: 'test' }) myFunction() //{value: 'test'}

How this works in arrow functions

this is a concept that can be complicated to grasp, as it varies a lot depending on the context and also varies depending on the mode of JavaScript (strict mode or not).

It’s important to clarify this concept because arrow functions behave very differently compared to regular functions.

When defined as a method of an object, in a regular function this refers to the object, so you can do:

const car = { model: 'Fiesta', manufacturer: 'Ford', fullName: function() { return `${this.manufacturer} ${this.model}` } }

calling car.fullName() will return "Ford Fiesta" .

The this scope with arrow functions is inherited from the execution context. An arrow function does not bind this at all, so its value will be looked up in the call stack, so in this code car.fullName() will not work, and will return the string "undefined undefined" :

const car = { model: 'Fiesta', manufacturer: 'Ford', fullName: () => { return `${this.manufacturer} ${this.model}` } }

Due to this, arrow functions are not suited as object methods.

Arrow functions cannot be used as constructors either, when instantiating an object will raise a TypeError .

This is where regular functions should be used instead, when dynamic context is not needed.

This is also a problem when handling events. DOM Event listeners set this to be the target element, and if you rely on this in an event handler, a regular function is necessary:

const link = document.querySelector('#link') link.addEventListener('click', () => { // this === window }) const link = document.querySelector('#link') link.addEventListener('click', function() { // this === link })

Rest and spread

You can expand an array, an object or a string using the spread operator ... .

Let’s start with an array example. Given

const a = [1, 2, 3]

you can create a new array using

const b = [...a, 4, 5, 6]

You can also create a copy of an array using

const c = [...a]

This works for objects as well. Clone an object with:

const newObj = { ...oldObj }

Using strings, the spread operator creates an array with each char in the string:

const hey = 'hey' const arrayized = [...hey] // ['h', 'e', 'y']

This operator has some pretty useful applications. The most important one is the ability to use an array as function argument in a very simple way:

const f = (foo, bar) => {} const a = [1, 2] f(...a)

(in the past you could do this using f.apply(null, a) but that's not as nice and readable)

The rest element is useful when working with array destructuring:

const numbers = [1, 2, 3, 4, 5] [first, second, ...others] = numbers

and spread elements:

const numbers = [1, 2, 3, 4, 5] const sum = (a, b, c, d, e) => a + b + c + d + e const sumOfNumbers = sum(...numbers)

ES2018 introduces rest properties, which are the same but for objects.

Rest properties:

const { first, second, ...others } = { first: 1, second: 2, third: 3, fourth: 4, fifth: 5 } first // 1 second // 2 others // { third: 3, fourth: 4, fifth: 5 }

Spread properties allow to create a new object by combining the properties of the object passed after the spread operator:

const items = { first, second, ...others } items //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }

Object and array destructuring

Given an object, using the destructuring syntax you can extract just some values and put them into named variables:

const person = { firstName: 'Tom', lastName: 'Cruise', actor: true, age: 54 //made up } const { firstName: name, age } = person //name: Tom, age: 54

name and age contain the desired values.

The syntax also works on arrays:

const a = [1, 2, 3, 4, 5] const [first, second] = a

This statement creates 3 new variables by getting the items with index 0, 1, 4 from the array a :

const [first, second, , , fifth] = a

Template literals

Template Literals are a new ES2015 / ES6 feature that allows you to work with strings in a novel way compared to ES5 and below.

The syntax at a first glance is very simple, just use backticks instead of single or double quotes:

const a_string = `something`

They are unique because they provide a lot of features that normal strings built with quotes do not, in particular:

they offer a great syntax to define multiline strings

they provide an easy way to interpolate variables and expressions in strings

they allow you to create DSLs with template tags (DSL means domain specific language, and it’s for example used in React by Styled Components, to define CSS for a component)

Let’s dive into each of these in detail.

Multiline strings

Pre-ES6, to create a string spanning over two lines you had to use the \ character at the end of a line:

const string = 'first part \ second part'

This allows to create a string on 2 lines, but it’s rendered on just one line:

first part second part

To render the string on multiple lines as well, you explicitly need to add

at the end of each line, like this:

const string = 'first line

\ second line'

or

const string = 'first line

' + 'second line'

Template literals make multiline strings much simpler.

Once a template literal is opened with the backtick, you just press enter to create a new line, with no special characters, and it’s rendered as-is:

const string = `Hey this string is awesome!`

Keep in mind that space is meaningful, so doing this:

const string = `First Second`

is going to create a string like this:

First Second

an easy way to fix this problem is by having an empty first line, and appending the trim() method right after the closing backtick, which will eliminate any space before the first character:

const string = ` First Second`.trim()

Interpolation

Template literals provide an easy way to interpolate variables and expressions into strings.

You do so by using the ${...} syntax:

const myVariable = 'test' const string = `something ${myVariable}` //something test

inside the ${} you can add anything, even expressions:

const string = `something ${1 + 2 + 3}` const string2 = `something ${foo() ? 'x' : 'y'}`

Classes

In 2015 the ECMAScript 6 (ES6) standard introduced classes.

JavaScript has a quite uncommon way to implement inheritance: prototypical inheritance. Prototypal inheritance, while in my opinion great, is unlike most other popular programming language’s implementation of inheritance, which is class-based.

People coming from Java or Python or other languages had a hard time understanding the intricacies of prototypal inheritance, so the ECMAScript committee decided to sprinkle syntactic sugar on top of prototypical inheritance so that it resembles how class-based inheritance works in other popular implementations.

This is important: JavaScript under the hood is still the same, and you can access an object prototype in the usual way.

A class definition

This is how a class looks.

class Person { constructor(name) { this.name = name } hello() { return 'Hello, I am ' + this.name + '.' } }

A class has an identifier, which we can use to create new objects using new ClassIdentifier() .

When the object is initialized, the constructor method is called, with any parameters passed.

A class also has as many methods as it needs. In this case hello is a method and can be called on all objects derived from this class:

const flavio = new Person('Flavio') flavio.hello()

Class inheritance

A class can extend another class, and objects initialized using that class inherit all the methods of both classes.

If the inherited class has a method with the same name as one of the classes higher in the hierarchy, the closest method takes precedence:

class Programmer extends Person { hello() { return super.hello() + ' I am a programmer.' } } const flavio = new Programmer('Flavio') flavio.hello()

(the above program prints “Hello, I am Flavio. I am a programmer.”)

Classes do not have explicit class variable declarations, but you must initialize any variable in the constructor.

Inside a class, you can reference the parent class calling super() .

Static methods

Normally methods are defined on the instance, not on the class.

Static methods are executed on the class instead:

class Person { static genericHello() { return 'Hello' } } Person.genericHello() //Hello

Private methods

JavaScript does not have a built-in way to define private or protected methods.

There are workarounds, but I won’t describe them here.

Getters and setters

You can add methods prefixed with get or set to create a getter and setter, which are two different pieces of code that are executed based on what you are doing: accessing the variable, or modifying its value.

class Person { constructor(name) { this.name = name } set name(value) { this.name = value } get name() { return this.name } }

If you only have a getter, the property cannot be set, and any attempt at doing so will be ignored:

class Person { constructor(name) { this.name = name } get name() { return this.name } }

If you only have a setter, you can change the value but not access it from the outside:

class Person { constructor(name) { this.name = name } set name(value) { this.name = value } }

Callbacks

Computers are asynchronous by design.

Asynchronous means that things can happen independently of the main program flow.

In the current consumer computers, every program runs for a specific time slot, and then it stops its execution to let another program continue its execution. This thing runs in a cycle so fast that’s impossible to notice, and we think our computers run many programs simultaneously, but this is an illusion (except on multiprocessor machines).

Programs internally use interrupts, a signal that’s emitted to the processor to gain the attention of the system.

I won’t go into the internals of this, but just keep in mind that it’s normal for programs to be asynchronous, and halt their execution until they need attention, and the computer can execute other things in the meantime. When a program is waiting for a response from the network, it cannot halt the processor until the request finishes.

Normally, programming languages are synchronous, and some provide a way to manage asynchronicity, in the language or through libraries. C, Java, C#, PHP, Go, Ruby, Swift, Python, they are all synchronous by default. Some of them handle async by using threads, spawning a new process.

JavaScript is synchronous by default and is single threaded. This means that code cannot create new threads and run in parallel.

Lines of code are executed in series, one after another, for example:

const a = 1 const b = 2 const c = a * b console.log(c) doSomething()

But JavaScript was born inside the browser, its main job, in the beginning, was to respond to user actions, like onClick , onMouseOver , onChange , onSubmit and so on. How could it do this with a synchronous programming model?

The answer was in its environment. The browser provides a way to do it by providing a set of APIs that can handle this kind of functionality.

More recently, Node.js introduced a non-blocking I/O environment to extend this concept to file access, network calls and so on.

You can’t know when a user is going to click a button, so what you do is, you define an event handler for the click event. This event handler accepts a function, which will be called when the event is triggered:

document.getElementById('button').addEventListener('click', () => { //item clicked })

This is the so-called callback.

A callback is a simple function that’s passed as a value to another function, and will only be executed when the event happens. We can do this because JavaScript has first-class functions, which can be assigned to variables and passed around to other functions (called higher-order functions)

It’s common to wrap all your client code in a load event listener on the window object, which runs the callback function only when the page is ready:

window.addEventListener('load', () => { //window loaded //do what you want })

Callbacks are used everywhere, not just in DOM events.

One common example is by using timers:

setTimeout(() => { // runs after 2 seconds }, 2000)

XHR requests also accept a callback, in this example by assigning a function to a property that will be called when a particular event occurs (in this case, the state of the request changes):

const xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr.readyState === 4) { xhr.status === 200 ? console.log(xhr.responseText) : console.error('error') } } xhr.open('GET', 'https://yoursite.com') xhr.send()

Handling errors in callbacks

How do you handle errors with callbacks? One very common strategy is to use what Node.js adopted: the first parameter in any callback function is the error object: error-first callbacks

If there is no error, the object is null . If there is an error, it contains some description of the error and other information.

fs.readFile('/file.json', (err, data) => { if (err !== null) { //handle error console.log(err) return } //no errors, process data console.log(data) })

The problem with callbacks

Callbacks are great for simple cases!

However every callback adds a level of nesting, and when you have lots of callbacks, the code starts to be complicated very quickly:

window.addEventListener('load', () => { document.getElementById('button').addEventListener('click', () => { setTimeout(() => { items.forEach(item => { //your code here }) }, 2000) }) })

This is just a simple 4-levels code, but I’ve seen much more levels of nesting and it’s not fun.

How do we solve this?

ALTERNATIVES TO CALLBACKS

Starting with ES6, JavaScript introduced several features that help us with asynchronous code that do not involve using callbacks:

Promises (ES6)

Async/Await (ES8)

Promises

Promises are one way to deal with asynchronous code, without writing too many callbacks in your code.

Although they’ve been around for years, they were standardized and introduced in ES2015, and now they have been superseded in ES2017 by async functions.

Async functions use the promises API as their building block, so understanding them is fundamental even if in newer code you’ll likely use async functions instead of promises.

How promises work, in brief

Once a promise has been called, it will start in pending state. This means that the caller function continues the execution, while it waits for the promise to do its own processing, and give the caller function some feedback.

At this point, the caller function waits for it to either return the promise in a resolved state, or in a rejected state, but as you know JavaScript is asynchronous, so the function continues its execution while the promise does it work.

Which JS API use promises?

In addition to your own code and library code, promises are used by standard modern Web APIs like Fetch or Service Workers.

It’s unlikely that in modern JavaScript you’ll find yourself not using promises, so let’s start diving right into them.

Creating a promise

The Promise API exposes a Promise constructor, which you initialize using new Promise() :

let done = true const isItDoneYet = new Promise((resolve, reject) => { if (done) { const workDone = 'Here is the thing I built' resolve(workDone) } else { const why = 'Still working on something else' reject(why) } })

As you can see the promise checks the done global constant, and if that's true, we return a resolved promise, otherwise a rejected promise.

Using resolve and reject we can communicate back a value, in the above case we just return a string, but it could be an object as well.

Consuming a promise

In the last section, we introduced how a promise is created.

Now let’s see how the promise can be consumed or used.

const isItDoneYet = new Promise() //... const checkIfItsDone = () => { isItDoneYet .then(ok => { console.log(ok) }) .catch(err => { console.error(err) }) }

Running checkIfItsDone() will execute the isItDoneYet() promise and will wait for it to resolve, using the then callback, and if there is an error, it will handle it in the catch callback.

Chaining promises

A promise can be returned to another promise, creating a chain of promises.

A great example of chaining promises is given by the Fetch API, a layer on top of the XMLHttpRequest API, which we can use to get a resource and queue a chain of promises to execute when the resource is fetched.

The Fetch API is a promise-based mechanism, and calling fetch() is equivalent to defining our own promise using new Promise() .

Example:

const status = response => { if (response.status >= 200 && response.status < 300) { return Promise.resolve(response) } return Promise.reject(new Error(response.statusText)) } const json = response => response.json() fetch('/todos.json') .then(status) .then(json) .then(data => { console.log('Request succeeded with JSON response', data) }) .catch(error => { console.log('Request failed', error) })

In this example, we call fetch() to get a list of TODO items from the todos.json file found in the domain root, and we create a chain of promises.

Running fetch() returns a response, which has many properties, and within those we reference:

status , a numeric value representing the HTTP status code

, a numeric value representing the HTTP status code statusText , a status message, which is OK if the request succeeded

response also has a json() method, which returns a promise that will resolve with the content of the body processed and transformed into JSON.

So given those premises, this is what happens: the first promise in the chain is a function that we defined, called status() , that checks the response status and if it's not a success response (between 200 and 299), it rejects the promise.

This operation will cause the promise chain to skip all the chained promises listed and will skip directly to the catch() statement at the bottom, logging the Request failed text along with the error message.

If that succeeds instead, it calls the json() function we defined. Since the previous promise, when successful, returned the response object, we get it as an input to the second promise.

In this case, we return the data JSON processed, so the third promise receives the JSON directly:

.then((data) => { console.log('Request succeeded with JSON response', data) })

and we simply log it to the console.

Handling errors

In the above example, in the previous section, we had a catch that was appended to the chain of promises.

When anything in the chain of promises fails and raises an error or rejects the promise, the control goes to the nearest catch() statement down the chain.

new Promise((resolve, reject) => { throw new Error('Error') }).catch(err => { console.error(err) }) // or new Promise((resolve, reject) => { reject('Error') }).catch(err => { console.error(err) })

Cascading errors

If inside the catch() you raise an error, you can append a second catch() to handle it, and so on.

new Promise((resolve, reject) => { throw new Error('Error') }) .catch(err => { throw new Error('Error') }) .catch(err => { console.error(err) })

Orchestrating promises with Promise.all()

If you need to synchronize different promises, Promise.all() helps you define a list of promises, and execute something when they are all resolved.

Example:

const f1 = fetch('/something.json') const f2 = fetch('/something2.json') Promise.all([f1, f2]) .then(res => { console.log('Array of results', res) }) .catch(err => { console.error(err) })

The ES2015 destructuring assignment syntax allows you to also do

Promise.all([f1, f2]).then(([res1, res2]) => { console.log('Results', res1, res2) })

You are not limited to using fetch of course, any promise is good to go.

Orchestrating promises with Promise.race()

Promise.race() runs as soon as one of the promises you pass to it resolves, and it runs the attached callback just once with the result of the first promise resolved.

Example:

const promiseOne = new Promise((resolve, reject) => { setTimeout(resolve, 500, 'one') }) const promiseTwo = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'two') }) Promise.race([promiseOne, promiseTwo]).then(result => { console.log(result) // 'two' })

Async/Await

JavaScript evolved in a very short time from callbacks to promises (ES2015), and since ES2017 asynchronous JavaScript is even simpler with the async/await syntax.

Async functions are a combination of promises and generators, and basically, they are a higher level abstraction over promises. Let me repeat: async/await is built on promises.

Why were async/await introduced?

They reduce the boilerplate around promises, and the “don’t break the chain” limitation of chaining promises.

When Promises were introduced in ES2015, they were meant to solve a problem with asynchronous code, and they did, but over the 2 years that separated ES2015 and ES2017, it was clear that promises could not be the final solution.

Promises were introduced to solve the famous callback hell problem, but they introduced complexity on their own, and syntax complexity.

They were good primitives around which a better syntax could be exposed to developers, so when the time was right we got async functions.

They make the code look like it’s synchronous, but it’s asynchronous and non-blocking behind the scenes.

How it works

An async function returns a promise, like in this example:

const doSomethingAsync = () => { return new Promise(resolve => { setTimeout(() => resolve('I did something'), 3000) }) }

When you want to call this function you prepend await , and the calling code will stop until the promise is resolved or rejected. One caveat: the client function must be defined as async . Here's an example:

const doSomething = async () => { console.log(await doSomethingAsync()) }

A quick example

This is a simple example of async/await used to run a function asynchronously:

const doSomethingAsync = () => { return new Promise(resolve => { setTimeout(() => resolve('I did something'), 3000) }) } const doSomething = async () => { console.log(await doSomethingAsync()) } console.log('Before') doSomething() console.log('After')

The above code will print the following to the browser console:

Before After I did something //after 3s

Promise all the things

Prepending the async keyword to any function means that the function will return a promise.

Even if it’s not doing so explicitly, it will internally make it return a promise.

This is why this code is valid:

const aFunction = async () => { return 'test' } aFunction().then(alert) // This will alert 'test'

and it’s the same as:

const aFunction = async () => { return Promise.resolve('test') } aFunction().then(alert) // This will alert 'test'

The code is much simpler to read

As you can see in the example above, our code looks very simple. Compare it to code using plain promises, with chaining and callback functions.

And this is a very simple example, the major benefits will arise when the code is much more complex.

For example here’s how you would get a JSON resource, and parse it, using promises:

const getFirstUserData = () => { return fetch('/users.json') // get users list .then(response => response.json()) // parse JSON .then(users => users[0]) // pick first user .then(user => fetch(`/users/${user.name}`)) // get user data .then(userResponse => userResponse.json()) // parse JSON } getFirstUserData()

And here is the same functionality provided using await/async:

const getFirstUserData = async () => { const response = await fetch('/users.json') // get users list const users = await response.json() // parse JSON const user = users[0] // pick first user const userResponse = await fetch(`/users/${user.name}`) // get user data const userData = await userResponse.json() // parse JSON return userData } getFirstUserData()

Multiple async functions in series

Async functions can be chained very easily, and the syntax is much more readable than with plain promises:

const promiseToDoSomething = () => { return new Promise(resolve => { setTimeout(() => resolve('I did something'), 10000) }) } const watchOverSomeoneDoingSomething = async () => { const something = await promiseToDoSomething() return something + ' and I watched' } const watchOverSomeoneWatchingSomeoneDoingSomething = async () => { const something = await watchOverSomeoneDoingSomething() return something + ' and I watched as well' } watchOverSomeoneWatchingSomeoneDoingSomething().then(res => { console.log(res) })

Will print:

I did something and I watched and I watched as well

Easier debugging

Debugging promises is hard because the debugger will not step over asynchronous code.

Async/await makes this very easy because to the compiler it’s just like synchronous code.

ES Modules

ES Modules is the ECMAScript standard for working with modules.

While Node.js has been using the CommonJS standard for years, the browser never had a module system, as every major decision such as a module system must be first standardized by ECMAScript and then implemented by the browser.

This standardization process completed with ES6 and browsers started implementing this standard trying to keep everything well aligned, working all in the same way, and now ES Modules are supported in Chrome, Safari, Edge and Firefox (since version 60).

Modules are very cool, because they let you encapsulate all sorts of functionality, and expose this functionality to other JavaScript files, as libraries.

The ES Modules Syntax

The syntax to import a module is:

import package from 'module-name'

while CommonJS uses

const package = require('module-name')

A module is a JavaScript file that exports one or more values (objects, functions or variables), using the export keyword. For example, this module exports a function that returns a string uppercase:

uppercase.js

export default str => str.toUpperCase()

In this example, the module defines a single, default export, so it can be an anonymous function. Otherwise it would need a name to distinguish it from other exports.

Now, any other JavaScript module can import the functionality offered by uppercase.js by importing it.

An HTML page can add a module by using a <scri pt> tag with the sp ecial type="m odule" attribute:

<script type="module" src="index.js"><;/script>

Note: this module import behaves like a defer script load. See efficiently load JavaScript with defer and async

It’s important to note that any script loaded with type="module" is loaded in strict mode.

In this example, the uppercase.js module defines a default export, so when we import it, we can assign it a name we prefer:

import toUpperCase from './uppercase.js'

and we can use it:

toUpperCase('test') //'TEST'

You can also use an absolute path for the module import, to reference modules defined on another domain:

import toUpperCase from 'https://flavio-es-modules-example.glitch.me/uppercase.js'

This is also valid import syntax:

import { foo } from '/uppercase.js'import { foo } from '../uppercase.js'

This is not:

import { foo } from 'uppercase.js' import { foo } from 'utils/uppercase.js'

It’s either absolute, or has a ./ or / before the name.

Other import/export options

We saw this example above:

export default str => str.toUpperCase()

This creates one default export. In a file however you can export more than one thing, by using this syntax:

const a = 1 const b = 2 const c = 3 export { a, b, c }

Another module can import all those exports using

import * from 'module'

You can import just a few of those exports, using the destructuring assignment:

import { a } from 'module' import { a, b } from 'module'

You can rename any import, for convenience, using as :

import { a, b as two } from 'module'

You can import the default export, and any non-default export by name, like in this common React import:

import React, { Component } from 'react'

You can see an ES Modules example here: https://glitch.com/edit/#!/flavio-es-modules-example?path=index.html

CORS

Modules are fetched using CORS. This means that if you reference scripts from other domains, they must have a valid CORS header that allows cross-site loading (like Access-Control-Allow-Origin: * )

What about browsers that do not support modules?

Use a combination of type="module" and nomodule :

<script type="module" src="module.js"></script> <script nomodule src="fallback.js"></script>

ES Modules are one of the biggest features introduced in modern browsers. They are part of ES6 but the road to implement them has been long.

We can now use them! But we must also remember that having more than a few modules is going to have a performance hit on our pages, as it’s one more step that the browser must perform at runtime.

Webpack is probably going to still be a huge player even if ES Modules land in the browser, but having such a feature directly built in the language is huge for a unification of how modules work client-side and on Node.js as well.

SECTION 2: REACT CONCEPTS

Single Page Applications

React Applications are also called Single Page Applications. What does this mean?

In the past, when browsers were much less capable than today, and JavaScript performance was poor, every page was coming from a server. Every time you clicked something, a new request was made to the server and the browser subsequently loaded the new page.

Only very innovative products worked differently, and experimented with new approaches.

Today, popularized by modern frontend JavaScript frameworks like React, an app is usually built as a single page application: you only load the application code (HTML, CSS, JavaScript) once, and when you interact with the application, what generally happens is that JavaScript intercepts the browser events and instead of making a new request to the server that then returns a new document, the client requests some JSON or performs an action on the server but the page that the user sees is never completely wiped away, and behaves more like a desktop application.

Single page applications are built in JavaScript (or at least compiled to JavaScript) and work in the browser.

The technology is always the same, but the philosophy and some key components of how the application works are different.

Examples of Single Page Applications

Some notable examples:

Gmail

Google Maps

Facebook

Twitter

Google Drive

Pros and cons of SPAs

An SPA feels much faster to the user, because instead of waiting for the client-server communication to happen, and wait for the browser to re-render the page, you can now have instant feedback. This is the responsibility of the application maker, but you can have transitions and spinners and any kind of UX improvement that is certainly better than the traditional workflow.

In addition to making the experience faster to the user, the server will consume less resources because you can focus on providing an efficient API instead of building the layouts server-side.

This makes it ideal if you also build a mobile app on top of the API, as you can completely reuse your existing server-side code.

Single Page Applications are easy to transform into Progressive Web Apps, which in turn enables you to provide local caching and to support offline experiences for your services (or simply a better error message if your users need to be online).

SPAs are best used when there is no need for SEO (search engine optimization). For example for apps that work behind a login.

Search engines, while improving every day, still have trouble indexing sites built with an SPA approach rather than the traditional server-rendered pages. This is the case for blogs. If you are going to rely on search engines, don’t even bother with creating a single page application without having a server rendered part as well.

When coding an SPA, you are going to write a great deal of JavaScript. Since the app can be long-running, you are going to need to pay a lot more attention to possible memory leaks — if in the past your page had a lifespan that was counted in minutes, now an SPA might stay open for hours at a time and if there is any memory issue that’s going to increase the browser memory usage by a lot more and it’s going to cause an unpleasantly slow experience if you don’t take care of it.

SPAs are great when working in teams. Backend developers can just focus on the API, and frontend developers can focus on creating the best user experience, making use of the API built in the backend.

As a con, Single Page Apps rely heavily on JavaScript. This might make using an application running on low power devices a poor experience in terms of speed. Also, some of your visitors might just have JavaScript disabled, and you also need to consider accessibility for anything you build.

Overriding the navigation

Since you get rid of the default browser navigation, URLs must be managed manually.

This part of an application is called the router. Some frameworks already take care of them for you (like Ember), others require libraries that will do this job (like React Router).

What’s the problem? In the beginning, this was an afterthought for developers building Single Page Applications. This caused the common “broken back button” issue: when navigating inside the application the URL didn’t change (since the browser default navigation was hijacked) and hitting the back button, a common operation that users do to go to the previous screen, might move to a website you visited a long time ago.

This problem can now be solved using the History API offered by browsers, but most of the time you’ll use a library that internally uses that API, like React Router.

Declarative

What does it mean when you read that React is declarative? You’ll run across articles describing React as a declarative approach to building UIs.

React made its “declarative approach” quite popular and upfront so it permeated the frontend world along with React.

It’s really not a new concept, but React took building UIs a lot more declaratively than with HTML templates:

you can build Web interfaces without even touching the DOM directly

you can have an event system without having to interact with the actual DOM Events.

The opposite of declarative is imperative. A common example of an imperative approach is looking up elements in the DOM using jQuery or DOM events. You tell the browser exactly what to do, instead of telling it what you need.

The React declarative approach abstracts that for us. We just tell React we want a component to be rendered in a specific way, and we never have to interact with the DOM to reference it later.

Immutability

One concept you will likely meet when programming in React is immutability (and its opposite, mutability).

It’s a controversial topic, but whatever you might think about the concept of immutability, React and most of its ecosystem kind of forces this, so you need to at least have a grasp of why it’s so important and the implications of it.

In programming, a variable is immutable when its value cannot change after it’s created.

You are already using immutable variables without knowing it when you manipulate a string. Strings are immutable by default, when you change them in reality you create a new string and assign it to the same variable name.

An immutable variable can never be changed. To update its value, you create a new variable.

The same applies to objects and arrays.

Instead of changing an array, to add a new item you create a new array by concatenating the old array, plus the new item.

An object is never updated, but copied before changing it.

This applies to React in many places.

For example, you should never mutate the state property of a component directly, but only through the setState() method.

In Redux, you never mutate the state directly, but only through reducers, which are functions.

The question is, why?

There are various reasons, the most important of which are:

Mutations can be centralized, like in the case of Redux, which improves your debugging capabilities and reduces sources of errors.

Code looks cleaner and simpler to understand. You never expect a function to change some value without you knowing, which gives you predictability . When a function does not mutate objects but just returns a new object, it’s called a pure function.

. When a function does not mutate objects but just returns a new object, it’s called a pure function. The library can optimize the code because for example JavaScript is faster when swapping an old object reference for an entirely new object, rather than mutating an existing object. This gives you performance.

Purity

In JavaScript, when a function does not mutate objects but just returns a new object, it’s called a pure function.

A function, or a method, in order to be called pure should not cause side effects and should return the same output when called multiple times with the same input.

A pure function takes an input and returns an output without changing the input nor anything else.

Its output is only determined by the arguments. You could call this function 1M times, and given the same set of arguments, the output will always be the same.

React applies this concept to components. A React component is a pure component when its output is only dependant on its props.

All functional components are pure components:

const Button = props => { return <button>{props.message}</button> }

Class components can be pure if their output only depends on the props:

class Button extends React.Component { render() { return <button>{this.props.message}</button> } }

Composition

In programming, composition allows you to build more complex functionality by combining small and focused functions.

For example, think about using map() to create a new array from an initial set, and then filtering the result using filter() :

const list = ['Apple', 'Orange', 'Egg'] list.map(item => item[0]).filter(item => item === 'A') //'A'

In React, composition allows you to have some pretty cool advantages.

You create small and lean components and use them to compose more functionality on top of them. How?

Create specialized version of a component

Use an outer component to expand and specialize a more generic component:

const Button = props => { return <button>{props.text}</button> } const SubmitButton = () => { return <Button text="Submit" /> } const LoginButton = () => { return <Button text="Login" /> }

Pass methods as props

A component can focus on tracking a click event, for example, and what actually happens when the click event happens is up to the container component:

const Button = props => { return <button onClick={props.onClickHandler}>{props.text}</button> } const LoginButton = props => { return <Button text="Login" onClickHandler={props.onClickHandler} /> } const Container = () => { const onClickHandler = () => { alert('clicked') } return <LoginButton onClickHandler={onClickHandler} /> }

Using children

The props.children property allows you to inject components inside other components.

The component needs to output props.children in its JSX:

const Sidebar = props => { return <aside>{props.children}</aside> }

and you embed more components into it in a transparent way:

<Sidebar> <Link title="First link" /> <Link title="Second link" /> </Sidebar>

Higher order components

When a component receives a component as a prop and returns a component, it’s called higher order component.

We’ll see them in a little while.

The Virtual DOM

Many existing frameworks, before React came on the scene, were directly manipulating the DOM on every change.

First, what is the DOM?

The DOM (Document Object Model) is a Tree representation of the page, starting from the <ht ml> tag, going down into every child, which are called nodes.

It’s kept in the browser memory, and directly linked to what you see in a page. The DOM has an API that you can use to traverse it, access every single node, filter them, modify them.

The API is the familiar syntax you have likely seen many times, if you were not using the abstract API provided by jQuery and friends:

document.getElementById(id) document.getElementsByTagName(name) document.createElement(name) parentNode.appendChild(node) element.innerHTML element.style.left element.setAttribute() element.getAttribute() element.addEventListener() window.content window.onload window.dump() window.scrollTo()

React keeps a copy of the DOM representation, for what concerns the React rendering: the Virtual DOM

The Virtual DOM Explained

Every time the DOM changes, the browser has to do two intensive operations: repaint (visual or content changes to an element that do not affect the layout and positioning relative to other elements) and reflow (recalculate the layout of a portion of the page — or the whole page layout).

React uses a Virtual DOM to help the browser use less resources when changes need to be done on a page.

When you call setState() on a Component, specifying a state different than the previous one, React marks that Component as dirty. This is key: React only updates when a Component changes the state explicitly.

What happens next is:

React updates the Virtual DOM relative to the components marked as dirty (with some additional checks, like triggering shouldComponentUpdate() )

) Runs the diffing algorithm to reconcile the changes

Updates the real DOM

Why is the Virtual DOM helpful: batching

The key thing is that React batches much of the changes and performs a unique update to the real DOM, by changing all the elements that need to be changed at the same time, so the repaint and reflow the browser must perform to render the changes are executed just once.

Unidirectional Data Flow

Working with React you might encounter the term Unidirectional Data Flow. What does it mean? Unidirectional Data Flow is not a concept unique to React, but as a JavaScript developer this might be the first time you hear it.

In general this concept means that data has one, and only one, way to be transferred to other parts of the application.

In React this means that:

state is passed to the view and to child components

actions are triggered by the view

actions can update the state

the state change is passed to the view and to child components

The view is a result of the application state. State can only change when actions happen. When actions happen, the state is updated.

Thanks to one-way bindings, data cannot flow in the opposite way (as would happen with two-way bindings, for example), and this has some key advantages:

it’s less error prone, as you have more control over your data

it’s easier to debug, as you know what is coming from where

it’s more efficient, as the library already knows what the boundaries are of each part of the system

A state is always owned by one Component. Any data that’s affected by this state can only affect Components below it: its children.

Changing state on a Component will never affect its parent, or its siblings, or any other Component in the application: just its children.

This is the reason that the state is often moved up in the Component tree, so that it can be shared between components that need to access it.

SECTION 3: IN-DEPTH REACT

JSX

JSX is a technology that was introduced by React.

Although React can work completely fine without using JSX, it’s an ideal technology to work with components, so React benefits a lot from JSX.

At first, you might think that using JSX is like mixing HTML and JavaScript (and as you’ll see CSS).

But this is not true, because what you are really doing when using JSX syntax is writing a declarative syntax of what a component UI should be.

And you’re describing that UI not using strings, but instead using JavaScript, which allows you to do many nice things.

A JSX primer

Here is how you define a h1 tag containing a string:

const element = <h1>Hello, world!</h1>

It looks like a strange mix of JavaScript and HTML, but in reality it’s all JavaScript.

What looks like HTML, is actually syntactic sugar for defining components and their positioning inside the markup.

Inside a JSX expression, attributes can be inserted very easily:

const myId = 'test' const element = <h1 id={myId}>Hello, world!</h1>

You just need to pay attention when an attribute has a dash ( - ) which is converted to camelCase syntax instead, and these 2 special cases:

class becomes className

becomes for becomes htmlFor

because they are reserved words in JavaScript.

Here’s a JSX snippet that wraps two components into a div tag:

<div> <BlogPostsList /> <Sidebar /> </div>

A tag always needs to be closed, because this is more XML than HTML (if you remember the XHTML days, this will be familiar, but since then the HTML5 loose syntax won). In this case a self-closing tag is used.

Notice how I wrapped the 2 components into a div . Why? Because the render() function can only return a single node, so in case you want to return 2 siblings, just add a parent. It can be any tag, not just div .

Transpiling JSX

A browser cannot execute JavaScript files containing JSX code. They must be first transformed to regular JS.

How? By doing a process called transpiling.

We already said that JSX is optional, because to every JSX line, a corresponding plain JavaScript alternative is available, and that’s what JSX is transpiled to.

For example the following two constructs are equivalent:

Plain JS

ReactDOM.render( React.DOM.div( { id: 'test' }, React.DOM.h1(null, 'A title'), React.DOM.p(null, 'A paragraph') ), document.getElementById('myapp') )

JSX

ReactDOM.render( <div id="test"> <h1>A title</h1> <p>A paragraph</p> </div>, document.getElementById('myapp') )

This very basic example is just the starting point, but you can already see how more complicated the plain JS syntax is compared to using JSX.

At the time of writing the most popular way to perform the transpilation is to use Babel, which is the default option when running create-react-app , so if you use it you don't have to worry, everything happens under the hood for you.

If you don’t use create-react-app you need to setup Babel yourself.

JS in JSX

JSX accepts any kind of JavaScript mixed into it.

Whenever you need to add some JS, just put it inside curly braces {} . For example here's how to use a constant value defined elsewhere:

const paragraph = 'A paragraph' ReactDOM.render( <div id="test"> <h1>A title</h1> <p>{paragraph}</p> </div>, document.getElementById('myapp') )

This is a basic example. Curly braces accept any JS code:

const paragraph = 'A paragraph' ReactDOM.render( <table> {rows.map((row, i) => { return <tr>{row.text}</tr> })} </table>, document.getElementById('myapp') )

As you can see we nested JavaScript inside JSX defined inside JavaScript nested in JSX. You can go as deep as you need.

HTML in JSX

JSX resembles HTML a lot, but it’s actually XML syntax.

In the end you render HTML, so you need to know a few differences between how you would define some things in HTML, and how you define them in JSX.

Just like in XHTML, if you have ever used it, you need to close all tags: no more <br> but instead use the self-closing tag: <br /> (the same goes for other tags)

camelCase is the new standard

In HTML you’ll find attributes without any case (e.g. onchange ). In JSX, they are renamed to their camelCase equivalent:

onchange => onChange

=> onclick => onClick

=> onsubmit => onSubmit

class becomes className

Due to the fact that JSX is JavaScript, and class is a reserved word, you can't write

<p class="description">

but you need to use

<p className="description">

The same applies to for which is translated to htmlFor .

CSS in React

JSX provides a cool way to define CSS.

If you have a little experience with HTML inline styles, at first glance you’ll find yourself pushed back 10 or 15 years, to a world where inline CSS was completely normal (nowadays it’s demonized and usually just a “quick fix” go-to solution).

JSX style is not the same thing: first of all, instead of accepting a string containing CSS properties, the JSX style attribute only accepts an object. This means you define properties in an object:

var divStyle = { color: 'white' } ReactDOM.render(<div style={divStyle}>Hello World!</div>, mountNode)

or

ReactDOM.render(<div style={{ color: 'white' }}>Hello World!</div>, mountNode)

The CSS values you write in JSX are slightly different from plain CSS:

the keys property names are camelCased

values are just strings

you separate each tuple with a comma

Why is this preferred over plain CSS / SASS / LESS?

CSS is an unsolved problem. Since its inception, dozens of tools around it rose and then fell. The main problem with JS is that there is no scoping and it’s easy to write CSS that is not enforced in any way, thus a “quick fix” can impact elements that should not be touched.

JSX allows components (defined in React for example) to completely encapsulate their style.

Is this the go-to solution?

Inline styles in JSX are good until you need to

write media queries style animations reference pseudo classes (e.g. :hover ) reference pseudo elements (e.g. ::first-letter )

In short, they cover the basics, but it’s not the final solution.

Forms in JSX

JSX adds some changes to how HTML forms work, with the goal of making things easier for the developer.

value and defaultValue

The value attribute always holds the current value of the field.

The defaultValue attribute holds the default value that was set when the field was created.

This helps solve some weird behavior of regular DOM interaction when inspecting input.value and input.getAttribute('value') returning one the current value and one the original default value.

This also applies to the textarea field, e.g.

<textarea>Some text</textarea>

but instead

<textarea defaultValue={'Some text'} />

For select fields, instead of using

<select> <option value="x" selected> ... </option> </select>

use

<select defaultValue="x"> <option value="x">...</option> </select>

A more consistent onChange

Passing a function to the onChange attribute you can subscribe to events on form fields.

It works consistently across fields, even radio , select and checkbox input fields fire a onChange event.

onChange also fires when typing a character into an input or textarea field.

JSX auto escapes

To mitigate the ever present risk of XSS exploits, JSX forces automatic escaping in expressions.

This means that you might run into issues when using an HTML entity in a string expression.

You expect the following to print © 2017 :

<p>{'© 2017'}</p>

But it’s not, it’s printing © 2017 because the string is escaped.

To fix this you can either move the entities outside the expression:

<p>© 2017</p>

or by using a constant that prints the Unicode representation corresponding to the HTML entity you need to print:

<p>{'\u00A9 2017'}</p>

White space in JSX

To add white space in JSX there are 2 rules:

Rule 1: Horizontal white space is trimmed to 1

If you have white space between elements in the same line, it’s all trimmed to 1 white space.

<p>Something becomes this</p>

becomes

<p>Something becomes this</p>

Rule 2: Vertical white space is eliminated

<p> Something becomes this </p>

becomes

<p>Somethingbecomesthis</p>

To fix this problem you need to explicitly add white space, by adding a space expression like this:

<p> Something {' '}becomes {' '}this </p>

or by embedding the string in a space expression:

<p> Something {' becomes '} this </p>

You can add comments to JSX by using the normal JavaScript comments inside an expression:

<p> {/* a comment */} { //another comment } </p>

Spread attributes

In JSX a common operation is assigning values to attributes.

Instead of doing it manually, e.g.

<div> <BlogPost title={data.title} date={data.date} /> </div>

you can pass

<div> <BlogPost {...data} /> </div>

and the properties of the data object will be used as attributes automatically, thanks to the ES6 spread operator.

How to loop in JSX

If you have a set of elements you need to loop upon to generate a JSX partial, you can create a loop, and then add JSX to an array:

const elements = [] //..some array const items = [] for (const [index, value] of elements.entries()) { items.push(<Element key={index} />) }

Now when rendering the JSX you can embed the items array simply by wrapping it in curly braces:

const elements = ['one', 'two', 'three']; const items = [] for (const [index, value] of elements.entries()) { items.push(<li key={index}>{value}</li>) } return ( <div> {items} </div> )

You can do the same directly in the JSX, using map instead of a for-of loop:

const elements = ['one', 'two', 'three']; return ( <ul> {elements.map((value, index) => { return <li key={index}>{value}</li> })} </ul> )

Components

A component is one isolated piece of interface. For example in a typical blog homepage you might find the Sidebar component, and the Blog Posts List component. They are in turn composed of components themselves, so you could have a list of Blog post components, each for every blog post, and each with its own peculiar properties.

React makes it very simple: everything is a component.

Even plain HTML tags are component on their own, and they are added by default.

The next 2 lines are equivalent, they do the same thing. One with JSX, one without, by injecting <h1>Hello World!</h1> into an element with id app .

import React from 'react' import ReactDOM from 'react-dom' ReactDOM.render(<h1>Hello World!</h1>, document.getElementById('app')) ReactDOM.render( React.DOM.h1(null, 'Hello World!'), document.getElementById('app') )

See, React.DOM exposed us an h1 component. Which other HTML tags are available? All of them! You can inspect what React.DOM offers by typing it in the Browser Console:

(the list is longer)

The built-in components are nice, but you’ll quickly outgrow them. What React excels in is letting us compose a UI by composing custom components.

Custom components

There are 2 ways to define a component in React.

A function component:

const BlogPostExcerpt = () => { return ( <div> <h1>Title</h1> <p>Description</p> </div> ) }

A class component:

import React, { Component } from 'react' class BlogPostExcerpt extends Component { render() { return ( <div> <h1>Title</h1> <p>Description</p> </div> ) } }

Up until recently, class components were the only way to define a component that had its own state, and could access the lifecycle methods so you could do things when the component was first rendered, updated or removed.

React Hooks changed this, so our function components are now much more powerful than ever and I believe we’ll see fewer and fewer class components in the future, although it will still be perfectly valid way to create components.

There is also a third syntax which uses the ES5 syntax, without the classes:

import React from 'react' React.createClass({ render() { return ( <div> <h1>Title</h1> <p>Description</p> </div> ) } })

You’ll rarely see this in modern, > ES6 codebases.

State

Setting the default state of a component

In the Component constructor, initialize this.state . For example the BlogPostExcerpt component might have a clicked state:

class BlogPostExcerpt extends Component { constructor(props) { super(props) this.state = { clicked: false } } render() { return ( <div> <h1>Title</h1> <p>Description</p> </div> ) } }

Accessing the state

The clicked state can be accessed by referencing this.state.clicked :

class BlogPostExcerpt extends Component { constructor(props) { super(props) this.state = { clicked: false } } render() { return ( <div> <h1>Title</h1> <p>Description</p> <p>Clicked: {this.state.clicked}</p> </div> ) } }

Mutating the state

A state should never be mutated by using

this.state.clicked = true

Instead, you should always use setState() instead, passing it an object:

this.setState({ clicked: true })

The object can contain a subset, or a superset, of the state. Only the properties you pass will be mutated, the ones omitted will be left in their current state.

Why you should always use setState()

The reason is that using this method, React knows that the state has changed. It will then start the series of events that will lead to the Component being re-rendered, along with any DOM update.

Unidirectional Data Flow

A state is always owned by one Component. Any data that’s affected by this state can only affect Components below it: its children.

Changing the state on a Component will never affect its parent, or its siblings, or any other Component in the application: just its children.

This is the reason the state is often moved up in the Component tree.

Moving the State Up in the Tree

Because of the Unidirectional Data Flow rule, if two components need to share state, the state needs to be moved up to a common ancestor.

Many times the closest ancestor is the best place to manage the state, but it’s not a mandatory rule.

The state is passed down to the components that need that value via props:

class Converter extends React.Component { constructor(props) { super(props) this.state = { currency: '€' } } render() { return ( <div> <Display currency={this.state.currency} /> <CurrencySwitcher currency={this.state.currency} /> </div> ) } }

The state can be mutated by a child component by passing a mutating function down as a prop:

class Converter extends React.Component { constructor(props) { super(props) this.state = { currency: '€' } } handleChangeCurrency = event => { this.setState({ currency: this.state.currency === '€' ? '$' : '€' }) } render() { return ( <div> <Display currency={this.state.currency} /> <CurrencySwitcher currency={this.state.currency} handleChangeCurrency={this.handleChangeCurrency} /> </div> ) } } const CurrencySwitcher = props => { return ( <button onClick={props.handleChangeCurrency}> Current currency is {props.currency}. Change it! </button> ) } const Display = props => { return <p>Current currency is {props.currency}.</p> }

Props

Props is how Components get their properties. Starting from the top component, every child component gets its props from the parent. In a function component, props is all it gets passed, and they are available by adding props as the function argument:

const BlogPostExcerpt = props => { return ( <div> <h1>{props.title}</h1> <p>{props.description}</p> </div> ) }

In a class component, props are passed by default. There is no need to add anything special, and they are accessible as this.props in a Component instance.

import React, { Component } from 'react' class BlogPostExcerpt extends Component { render() { return ( <div> <h1>{this.props.title}</h1> <p>{this.props.description}</p> </div> ) } }

Passing props down to child components is a great way to pass values around in your application. A component either holds data (has state) or receives data through its props.

It gets complicated when:

you need to access the state of a component from a child that’s several levels down (all the previous children need to act as a pass-through, even if they do not need to know the state, complicating things)

you need to access the state of a component from a completely unrelated component.

Default values for props

If any value is not required we need to specify a default value for it if it’s missing when the Component is initialized.

BlogPostExcerpt.propTypes = { title: PropTypes.string, description: PropTypes.string } BlogPostExcerpt.defaultProps = { title: '', description: '' }

Some tooling like ESLint have the ability to enforce defining the defaultProps for a Component with some propTypes not explicitly required.

How props are passed

When initializing a component, pass the props in a way similar to HTML attributes:

const desc = 'A description' //... <BlogPostExcerpt title="A blog post" description={desc} />

We passed the title as a plain string (something we can only do with strings!), and description as a variable.

Children

A special prop is children . That contains the value of anything that is passed in the body of the component, for example:

<BlogPostExcerpt title="A blog post" description="{desc}"> Something </BlogPostExcerpt>

In this case, inside BlogPostExcerpt we could access "Something" by looking up this.props.children .

While Props allow a Component to receive properties from its parent, to be “instructed” to print some data for example, state allows a component to take on life itself, and be independent of the surrounding environment.

Presentational vs container components

In React, components are often divided into 2 big buckets: presentational components and container components.

Each of those have their unique characteristics.

Presentational components are mostly concerned with generating some markup to be outputted.

They don’t manage any kind of state, except for state related the the presentation

Container components are mostly concerned with the “backend” operations.

They might handle the state of various sub-components. They might wrap several presentational components. They might interface with Redux.

As a way to simplify the distinction, we can say presentational components are concerned with the look, container components are concerned with making things work.

For example, this is a presentational component. It gets data from its props, and just focuses on showing an element:

const Users = props => ( <ul> {props.users.map(user => ( <li>{user}</li> ))} </ul> )

On the other hand this is a container component. It manages and stores its own data, and uses the presentational component to display it.

class UsersContainer extends React.Component { constructor() { this.state = { users: [] } } componentDidMount() { axios.get('/users').then(users => this.setState({ users: users })) ) } render() { return <Users users={this.state.users} /> } }

State vs props

In a React component, props are variables passed to it by its parent component. State on the other hand is still variables, but directly initialized and managed by the component.

The state can be initialized by props.

For example, a parent component might include a child component by calling

<ChildComponent />

The parent can pass a prop by using this syntax:

<ChildComponent color=green />

Inside the ChildComponent constructor we could access the prop:

class ChildComponent extends React.Component { constructor(props) { super(props) console.log(props.color) } }

and any other method in this class can reference the props using this.props .

Props can be used to set the internal state based on a prop value in the constructor, like this:

class ChildComponent extends React.Component { constructor(props) { super(props) this.state.colorName = props.color } }

Of course a component can also initialize the state without looking at props.

In this case there’s nothing useful going on, but imagine doing something different based on the prop value, probably setting a state value is best.

Props should never be changed in a child component, so if there’s something going on that alters some variable, that variable should belong to the component state.

Props are also used to allow child components to access methods defined in the parent component. This is a good way to centralize managing the state in the parent component, and avoid children having the need to have their own state.

Most of your components will just display some kind of information based on the props they received, and stay stateless.

PropTypes

Since JavaScript is a dynamically typed language, we don’t really have a way to enforce the type of a variable at compile time, and if we pass invalid types, they will fail at runtime or give weird results if the types are compatible but not what we expect.

Flow and TypeScript help a lot, but React has a way to directly help with props types, and even before running the code, our tools (editors, linters) can detect when we are passing the wrong values:

import PropTypes from 'prop-types' import React from 'react' class BlogPostExcerpt extends Component { render() { return ( <div> <h1>{this.props.title}</h1> <p>{this.props.description}</p> </div> ) } } BlogPostExcerpt.propTypes = { title: PropTypes.string, description: PropTypes.string } export default BlogPostExcerpt

Which types can we use

These are the fundamental types we can accept:

PropTypes.array

PropTypes.bool

PropTypes.func

PropTypes.number

PropTypes.object

PropTypes.string

PropTypes.symbol

We can accept one of two types:

PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),

We can accept one of many values:

PropTypes.oneOf(['Test1', 'Test2']),

We can accept an instance of a class:

PropTypes.instanceOf(Something)

We can accept any React node:

PropTypes.node

or even any type at all:

PropTypes.any

Arrays have a special syntax that we can use to accept an array of a particular type:

PropTypes.arrayOf(PropTypes.string)

We can compose object properties by using

PropTypes.shape({ color: PropTypes.string, fontSize: PropTypes.number })

Requiring properties

Appending isRequired to any PropTypes option will cause React to return an error if that property is missing:

PropTypes.arrayOf(PropTypes.string).isRequired, PropTypes.string.isRequired,

React Fragment

Notice how I wrap return values in a div . This is because a component can only return one single element, and if you want more than one, you need to wrap it with another container tag.

This, however, causes an unnecessary div in the output. You can avoid this by using React.Fragment :

import React, { Component } from 'react' class BlogPostExcerpt extends Component { render() { return ( <React.Fragment> <h1>{this.props.title}</h1> <p>{this.props.description}</p> </React.Fragment> ) } }

which also has a very nice shorthand syntax <></> that is supported only in recent releases (and Babel 7+):

import React, { Component } from 'react' class BlogPostExcerpt extends Component { render() { return ( <> <h1>{this.props.title}</h1> <p>{this.props.description}</p> </> ) } }

Events

React provides an easy way to manage events. Prepare to say goodbye to addEventListener .

In the previous article about the State you saw this example:

const CurrencySwitcher = props => { return ( <button onClick={props.handleChangeCurrency}> Current currency is {props.currency}. Change it! </button> ) }

If you’ve been using JavaScript for a while, this is just like plain old JavaScript event handlers, except that this time you’re defining everything in JavaScript, not in your HTML, and you’re passing a function, not a string.

The actual event names are a little bit different because in React you use camelCase for everything, so onclick becomes onClick , onsubmit becomes onSubmit .

For reference, this is old school HTML with JavaScript events mixed in:

<button onclick="handleChangeCurrency()">...<;/button>

Event handlers

It’s a convention to have event handlers defined as methods on the Component class:

class Converter extends React.Component { handleChangeCurrency = event => { this.setState({ currency: this.state.currency === '€' ? '$' : '€' }) } }

All handlers receive an event object that adheres, cross-browser, to the W3C UI Events spec.

Bind this in methods

If you use class components, don’t forget to bind methods. The methods of ES6 classes by default are not bound. What this means is that this is not defined unless you define methods as arrow functions:

class Converter extends React.Component { handleClick = e => { /* ... */ } //... }

when using the the property initializer syntax with Babel (enabled by default in create-react-app ), otherwise you need to bind it manually in the constructor:

class Converter extends React.Component { constructor(props) { super(props) this.handleClick = this.handleClick.bind(this) } handleClick(e) {} }

The events reference

There are lots of events supported, here’s a summary list.

Clipboard

onCopy

onCut

onPaste

Composition

onCompositionEnd

onCompositionStart

onCompositionUpdate

Keyboard

onKeyDown

onKeyPress

onKeyUp

Focus

onFocus

onBlur

Form

onChange

onInput

onSubmit

Mouse

onClick

onContextMenu

onDoubleClick

onDrag

onDragEnd

onDragEnter

onDragExit

onDragLeave

onDragOver

onDragStart

onDrop

onMouseDown

onMouseEnter

onMouseLeave

onMouseMove

onMouseOut

onMouseOver

onMouseUp

Selection

onSelect

Touch

onTouchCancel

onTouchEnd

onTouchMove

onTouchStart

UI

onScroll

Mouse Wheel

onWheel

Media

onAbort

onCanPlay

onCanPlayThrough

onDurationChange

onEmptied

onEncrypted

onEnded

onError

onLoadedData

onLoadedMetadata

onLoadStart

onPause

onPlay

onPlaying

onProgress

onRateChange

onSeeked

onSeeking

onStalled

onSuspend

onTimeUpdate

onVolumeChange

onWaiting

Image

onLoad

onError

Animation

onAnimationStart

onAnimationEnd

onAnimationIteration

Transition

onTransitionEnd

Lifecycle Events

React class components can have hooks for several lifecycle events.

Hooks allow function components to access them too, in a different way.

During the lifetime of a component, there’s a series of events that gets called, and to each event you can hook and provide custom functionality.

What hook is best for what functionality is something we’re going to see here.

First, there are 3 phases in a React component lifecycle:

Mounting

Updating

Unmounting

Let’s see those 3 phases in detail and the methods that get called for each.

Mounting

When mounting you have 4 lifecycle methods before the component is mounted in the DOM: the constructor , getDerivedStateFromProps , render and componentDidMount .

Constructor

The constructor is the first method that is called when mounting a component.

You usually use the constructor to set up the initial state using this.state = ... .

getDerivedStateFromProps()

When the state depends on props, getDerivedStateFromProps can be used to update the state based on the props value.

It was added in React 16.3, aiming to replace the componentWillReceiveProps deprecated method.

In this method you haven’t access to this as it's a static method.

It’s a pure method, so it should not cause side effects and should return the same output when called multiple times with the same input.

Returns an object with the updated elements of the state (or null if the state does not change)

render()

From the render() method you return the JSX that builds the component interface.

It’s a pure method, so it should not cause side effects and should return the same output when called multiple times with the same input.

componentDidMount()

This method is the one that you will use to perform API calls, or process operations on the DOM.

Updating

When updating you have 5 lifecycle methods before the component is mounted in the DOM: the getDerivedStateFromProps , shouldComponentUpdate , render , getSnapshotBeforeUpdate and componentDidUpdate .

getDerivedStateFromProps()

See the above description for this method.

This method returns a boolean, true or false . You use this method to tell React if it should go on with the rerendering, and defaults to true . You will return false when rerendering is expensive and you want to have more control on when this happens.

render()

See the above description for this method.

In this method you have access to the props and state of the previous render, and of the current render.

Its use cases are very niche, and it’s probably the one that you will use less.

This method is called when the component has been updated in the DOM. Use this to run any 3rd party DOM API or call APIs that must be updated when the DOM changes.

It corresponds to the componentDidMount() method from the mounting phase.

Unmounting

In this phase we only have one method, componentWillUnmount .

componentWillUnmount()

The method is called when the component is removed from the DOM. Use this to do any sort of cleanup you need to perform.

Legacy

If you are working on an app that uses componentWillMount , componentWillReceiveProps or componentWillUpdate , those were deprecated in React 16.3 and you should migrate to other lifecycle methods.

Forms in React

Forms are one of the few HTML elements that are interactive by default.

They were designed to allow the user to interact with a page.

Common uses of forms?

Search

Contact forms

Shopping carts checkout

Login and registration

and more!

Using React we can make our forms much more interactive and less static.

There are two main ways of handling forms in React, which differ on a fundamental level: how data is managed.

if the data is handled by the DOM, we call them uncontrolled components

if the data is handled by the components we call them controlled components

As you can imagine, controlled components is what you will use most of the time. The component state is the single source of truth, rather than the DOM. Some form fields are inherently uncontrolled because of their behavior, like the <input type="file"> field.

When an element state changes in a form field managed by a component, we track it using the onChange attribute.

class Form extends React.Component { constructor(props) { super(props) this.state = { username: '' } } handleChange(event) {} render() { return ( <form> Username: <input type="text" value={this.state.username} onChange={this.handleChange} /> </form> ) } }

In order to set the new state, we must bind this to the handleChange method, otherwise this is not accessible from within that method:

class Form extends React.Component { constructor(props) { super(props) this.state = { username: '' } this.handleChange = this.handleChange.bind(this) } handleChange(event) { this.setState({ value: event.target.value }) } render() { return ( <form> <input type="text" value={this.state.username} onChange={this.handleChange} /> </form> ) } }

Similarly, we use the onSubmit attribute on the form to call the handleSubmit method when the form is submitted:

class Form extends React.Component { constructor(props) { super(props) this.state = { username: '' } this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) } handleChange(event) { this.setState({ value: event.target.value }) } handleSubmit(event) { alert(this.state.username) event.preventDefault() } render() { return ( <form onSubmit={this.handleSubmit}> <input type="text" value={this.state.username} onChange={this.handleChange} /> <input type="submit" value="Submit" /> </form> ) } }

Validation in a form can be handled in the handleChange method: you have access to the old value of the state, and the new one. You can check the new value and if not valid reject the updated value (and communicate it in some way to the user).

HTML Forms are inconsistent. They have a long history, and it shows. React however makes things more consistent for us, and you can get (and update) fields using its value attribute.

Here’s a textarea , for example:

<textarea value={this.state.address} onChange={this.handleChange} />

The same goes for the select tag:

<select value="{this.state.age}" onChange="{this.handleChange}"> <option value="teen">Less than 18</option> <option value="adult">18+</option> </select>

Previously we mentioned the <input type="file"> field. That works a bit differently.

In this case you need to get a reference to the field by assigning the ref attribute to a property defined in the constructor with React.createRef() , and use that to get the value of it in the submit handler:

class FileInput extends React.Component { constructor(props) { super(props) this.curriculum = React.createRef() this.handleSubmit = this.handleSubmit.bind(this) } handleSubmit(event) { alert(this.curriculum.current.files[0].name) event.preventDefault() } render() { return ( <form onSubmit={this.handleSubmit}> <input type="file" ref={this.curriculum} /> <input type="submit" value="Submit" /> </form> ) } }

This is the uncontrolled components way. The state is stored in the DOM rather than in the component state (notice we used this.curriculum to access the uploaded file, and have not touched the state .

I know what you’re thinking — beyond those basics, there must be a library that simplifies all this form handling stuff and automates validation, error handling and more, right? There is a great one, Formik.

Reference a DOM element

React is great at abstracting away the DOM from you when building apps.

But what if you want to access the DOM element that a React component represents?

Maybe you have to add a library that interacts directly with the DOM like a chart library, maybe you need to call some DOM API, or add focus on an element.

Whatever the reason is, a good practice is making sure there’s no other way of doing so without accessing the DOM directly.

In the JSX of your component, you can assign the reference of the DOM element to a component property using this attribute:

ref={el => this.someProperty = el}

Put this into context, for example with a button element:

<button ref={el => (this.button = el)} />

button refers to a property of the component, which can then be used by the component's lifecycle methods (or other methods) to interact with the DOM:

class SomeComponent extends Component { render() { return <button ref={el => (this.button = el)} /> } }

In a function component the mechanism is the same, you just avoid using this (since it does not point to the component instance) and use a property instead:

function SomeComponent() { let button return <button ref={el => (button = el)} /> }

Server side rendering

Server Side Rendering, also called SSR, is the ability of a JavaScript application to render on the server rather than in the browser.

Why would we ever want to do so?

it allows your site to have a faster first page load time, which is the key to a good user experience

it is essential for SEO: search engines cannot (yet?) efficiently and correctly index applications that exclusively render client-side. Despite the latest improvements to indexing in Google, there are other search engines too, and Google is not perfect at it in any case. Also, Google favors sites with fast load times, and having to load client-side is not good for speed

it’s great when people share a page of your site on social media, as they can easily gather the metadata needed to nicely share the link (images, title, description..)

Without Server Side Rendering, all your server ships is an HTML page with no body, just some script tags that are then used by the browser to render the application.

Client-rendered apps are great at any subsequent user interaction after the first page load. Server Side Rendering allows us to get the sweet spot in the middle of client-rendered apps and backend-rendered apps: the page is generated server-side, but all interactions with the page once it’s been loaded are handled client-side.

However Server Side Rendering has its drawback too:

it’s fair to say that a simple SSR proof of concept is simple, but the complexity of SSR can grow with the complexity of your application

rendering a big application server-side can be quite resource-intensive, and under heavy load it could even provide a slower experience than client-side rendering, since you have a single bottleneck

A very simplistic example of what it takes to Server-Side render a React app

SSR setups can grow very, very complex and most tutorials will bake in Redux, React Router and many other concepts from the start.

To understand how SSR works, let’s start from the basics to implement a proof of concept.

Feel free to skip this paragraph if you just want to look into the libraries that provide SSR and not bother with the ground work

To implement basic SSR we’re going to use Express.

If you are new to Express, or need some catch-up, check out my free Express Handbook here: https://flaviocopes.com/page/ebooks/.

Warning: the complexity of SSR can grow with the complexity of your application. This is the bare minimum setup to render a basic React app. For more complex needs you might need to do a bit more work or also check out SSR libraries for React.

I assume you started a React app with create-react-app . If you are just trying, install one now using npx create-react-app ssr .

Go to the main app folder with the terminal, then run:

npm install express

You have a set of folders in your app directory. Create a new folder called server , then go into it and create a file named server.js .

Following the create-react-app conventions, the app lives in the src/App.js file. We're going to load that component, and render it to a string using ReactDOMServer.renderToString(), which is provided by react-dom .

You get the contents of the ./build/index.html file, and replace the <div id="root"></div> placeholder, which is the tag where the application hooks by default, with `<div id="root">\${ReactDOMServer.renderToString(<App />)}</div> .

All the content inside the build folder is going to be served as-is, statically by Express.

import path from 'path' import fs from 'fs' import express from 'express' import React from 'react' import ReactDOMServer from 'react-dom/server' import App from '../src/App' const PORT = 8080 const app = express() const router = express.Router() const serverRenderer = (req, res, next) => { fs.readFile(path.resolve('./build/index.html'), 'utf8', (err, data) => { if (err) { console.error(err) return res.status(500).send('An error occurred') } return res.send( data.replace( '<div id="root"></div>', `<div id="root">${ReactDOMServer.renderToString(<App />)}</div>` ) ) }) } router.use('^/$', serverRenderer) router.use( express.static(path.resolve(__dirname, '..', 'build'), { maxAge: '30d' }) ) // tell the app to use the above rules app.use(router) // app.use(express.static('./build')) app.listen(PORT, () => { console.log(`SSR running on port ${PORT}`) })

Now, in the client application, in your src/index.js , instead of calling ReactDOM.render() :

ReactDOM.render(<App />, document.getElementById('root'))

call ReactDOM.hydrate() , which is the same but has the additional ability to attach event listeners to existing markup once React loads:

ReactDOM.hydrate(<App />, document.getElementById('root'))

All the Node.js code needs to be transpiled by Babel, as server-side Node.js code does not know anything about JSX, nor ES Modules (which we use for the include statements).

Install these 3 packages:

npm install @babel/register @babel/preset-env @babel/preset-react ignore-styles express

ignore-styles is a Babel utility that will tell it to ignore CSS files imported using the import syntax.

Let’s create an entry point in server/index.js :

require('ignore-styles') require('@babel/register')({ ignore: [/(node_modules)/], presets: ['@babel/preset-env', '@babel/preset-react'] }) require('./server')

Build the React application, so that the build/ folder is populated:

npm run build

and let’s run this:

node server/index.js

I said this is a simplistic approach, and it is:

it does not handle rendering images correctly when using imports, which need Webpack in order to work (and which complicates the process a lot)

it does not handle page header metadata, which is essential for SEO and social sharing purposes (among other things)

So while this is a good example of using ReactDOMServer.renderToString() and ReactDOM.hydrate to get this basic server-side rendering, it's not enough for real world usage.

Server Side Rendering using libraries

SSR is hard to do right, and React has no de-facto way to implement it.

It’s still very much debatable if it’s worth the trouble, complication and overhead to get the benefits, rather than using a different technology to serve those pages. This discussion on Reddit has lots of opinions in that regard.

When Server Side Rendering is an important matter, my suggestion is to rely on pre-made libraries and tools that have had this goal in mind since the beginning.

In particular, I suggest Next.js and Gatsby, two projects we’ll see later on.

The Context API

The Context API is a neat way to pass state across the app without having to use props. It was introduced to allow you to pass state (and enable the state to update) across the app, without having to use props for it.

The React team suggests to stick to props if you have just a few levels of children to pass, because it’s still a much less complicated API than the Context API.

In many cases, it enables us to avoid using Redux, simplifying our apps a lot, and also learning how to use React.

How does it work?

You create a context using React.createContext() , which returns a Context object:

const { Provider, Consumer } = React.createContext()

Then you create a wrapper component that returns a Provider component, and you add as children all the components from which you want to access the context:

class Container extends React.Component { constructor(props) { super(props) this.state = { something: 'hey' } } render() { return ( <Provider value={{ state: this.state }}>{this.props.children}</Provider> ) } } class HelloWorld extends React.Component { render() 