Professional Documents
Culture Documents
of Contents
Introduction
Overview
Introduction to React
How to install React
Modern JavaScript core concepts you need to know to use React
How much JS you need to use React
Variables
Arrow functions
Work with objects and arrays using Rest and Spread
Object and array destructuring
Template literals
Classes
Callbacks
Promises
Async/Await
ES Modules
React Concepts
Single Page Apps
Declarative
Immutability
Purity
Composition
The Virtual DOM
Unidirectional Data Flow
In-depth
JSX
Components
State
Props
Presentational vs container components
2
State vs Props
PropTypes
Fragment
Events
Lifecycle events
Handling forms
Reference a DOM element
Server side rendering
Context API
Higher-order components
Render Props
Hooks
Code splitting
Practical examples
Build a simple counter
Fetch and display GitHub users information via API
Styling
CSS in React
SASS with React
Styled Components
Tooling
Babel
Webpack
Prettier
Testing
Introduction to Jest
Testing React Components
A look at the React Ecosystem
React Router
Redux
Next.js
Gatsby
Wrapping up
3
4
Introduction
Introduction
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. If you think some specific topic should be included, tell me.
In this book I make use of React hooks, so you need to set the required versions of React and
ReactDOM to use 16.7.0-alpha.2 (if when you're reading this Hooks are released officially,
you don't need to do this). You can do so in CodeSandbox by clicking "Add Dependency" and
searching react and choosing 16.7.0-alpha.2 from the select, and repeat this for react-
dom . When using create-react-app , run npm install react@16.7.0-alpha.2 react-dom@16.7.0-
I hope the contents of this book will help you achieve what you want: learn the basics of
React.
This book is written by Flavio. I publish web development tutorials every day on my website
flaviocopes.com.
5
Introduction
Enjoy!
6
Introduction to React
Introduction to React
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.
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 obviously is going to benefit a project if it turns out to be
successful.
7
Introduction to React
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.
React in itself has a very small API, and you basically need to understand 4 concepts to get
started:
Components
JSX
State
Props
8
How to 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.
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.7.0-alpha.2/umd/react.developme
nt.js"
crossorigin
></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0-alpha.2/umd/react-dom.p
roduction.min.js"
crossorigin
></script>
</body>
</html>
The 16.7.0-alpha.2 version in the links points to the latest Alpha of 16.7 (at the time of
writing), which has Hooks available. Please change it to the latest version of React that is
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.
9
How to install React
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>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
and load your scripts with the special text/babel MIME type:
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.
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.
10
How to install React
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.
11
How to install React
create-react-app created a files structure in the folder you told ( todolist in this case), and
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 .
12
How to install React
13
How to install React
npm run build : to build the React application files in the build folder, ready to be
deployed to a server
npm test : to run the testing suite using Jest
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.
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".
14
How to install 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
15
How to install React
and not
16
How much JS you need to use 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.
17
Variables
Variables
A variable is a literal assigned to an identifier, so you can reference and use
it later in the program. Learn how to declare one with JavaScript
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.
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 = 1
var a = 2
You can also declare multiple variables at once in the same statement:
18
Variables
var a = 1, b = 2
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
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'
19
Variables
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.
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.
20
Arrow functions
Arrow functions
Arrow Functions are one of the most impactful changes in ES6/ES2015, and
they are widely used nowadays. They slightly differ from regular functions.
Find out how
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:
to
If the function body contains just a single statement, you can omit the brackets and write all on
a single line:
If you have one (and just one) parameter, you could omit the parentheses completely:
Thanks to this short syntax, arrow functions encourage the use of small functions.
Implicit return
21
Arrow functions
Arrow functions allow you to have an implicit return: values are returned without having to use
the return keyword.
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:
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}`
}
}
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: () => {
22
Arrow functions
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:
23
Work with objects and arrays using Rest and Spread
You can expand an array, an object or a string using the spread operator ... .
const a = [1, 2, 3]
const b = [...a, 4, 5, 6]
const c = [...a]
Using strings, the spread operator creates an array with each char in the string:
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:
(in the past you could do this using f.apply(null, a) but that's not as nice and readable)
24
Work with objects and arrays using Rest and Spread
ES2018 introduces rest properties, which are the same but for objects.
Rest properties:
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:
25
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 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 :
26
Template literals
Template literals
Introduced in ES2015, aka ES6, Template Literals offer a new way to declare
strings, but also some new interesting constructs which are already widely
popular.
The syntax at a first glance is very simple, just use backticks instead of single or double
quotes:
They are unique because they provide a lot of features that normal strings built with quotes do
not, in particular:
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
27
Template literals
To render the string on multiple lines as well, you explicitly need to add \n at the end of each
line, like this:
const string =
'first line\n \
second line'
or
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:
string
is awesome!`
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
28
Template literals
Template literals provide an easy way to interpolate variables and expressions into strings.
Template tags
Tagged templates is one feature that might sound less useful at first for you, but it's actually
used by lots of popular libraries around, like Styled Components or Apollo, the GraphQL
client/server lib, so it's essential to understand how it works.
The styled.button and gql template tags highlighted in those examples are just functions:
this function returns a string, which can be the result of any kind of computation.
literals is an array containing the template literal content tokenized by the expressions
interpolations.
29
Template literals
literals is an array with two items. The first is something , the string until the first
interpolation, and the second is an empty string, the space between the end of the first
interpolation (we only have one) and the end of the string.
;`something
another `
;`
new line `
;`
test`
The function that is passed those values can do anything with them, and this is the power of
this kind feature.
The most simple example is replicating what the string interpolation does, by simply joining
literals and expressions :
30
Template literals
31
Classes
Classes
In 2015 the ECMAScript 6 (ES6) standard introduced classes. Learn all about
them
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:
32
Classes
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:
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.
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.
33
Classes
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
}
}
34
Classes
35
Callbacks
Callbacks
JavaScript is synchronous by default, and is single threaded. This means
that code cannot create new threads and run in parallel. Find out what
asynchronous code means and how it looks like
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
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()
36
Callbacks
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.
Callbacks
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
})
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
})
setTimeout(() => {
// runs after 2 seconds
}, 2000)
37
Callbacks
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):
If there is no error, the object is null . If there is an error, it contains some description of the
error and other information.
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)
})
38
Callbacks
})
This is just a simple 4-levels code, but I've seen much more levels of nesting and it's not fun.
Alternatives to callbacks
Starting with ES6, JavaScript introduced several features that help us with asynchronous code
that do not involve using callbacks: promises and async/await.
39
Promises
Promises
Promises are one way to deal with asynchronous code in JavaScript, without
writing too many callbacks in your code.
A promise is commonly defined as a proxy for a value that will eventually become
available.
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.
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.
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
40
Promises
The Promise API exposes a Promise constructor, which you initialize using new Promise() :
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.
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.
41
Promises
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() .
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:
response also has a json() method, which returns a promise that will resolve with the
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.
42
Promises
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)
})
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.
// or
Cascading errors
If inside the catch() you raise an error, you can append a second catch() to handle it, and
so on.
43
Promises
Orchestrating promises
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)
})
You are not limited to using fetch of course, any promise is good to go.
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:
44
Promises
Common errors
Uncaught TypeError: undefined is not a promise
If you get the Uncaught TypeError: undefined is not a promise error in the console, make sure
you use new Promise() instead of just Promise()
45
Async/Await
Async/Await
Discover the modern approach to asynchronous functions in JavaScript.
JavaScript evolved in a very short time from callbacks to Promises, and
since ES2017 asynchronous JavaScript is even simpler with the async/await
syntax
Introduction
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.
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:
46
Async/Await
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:
A quick example
This is a simple example of async/await used to run a function asynchronously:
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
Even if it's not doing so explicitly, it will internally make it return a promise.
47
Async/Await
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:
getFirstUserData()
getFirstUserData()
48
Async/Await
Async functions can be chained very easily, and the syntax is much more readable than with
plain promises:
watchOverSomeoneWatchingSomeoneDoingSomething().then(res => {
console.log(res)
})
Will print:
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.
49
ES Modules
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
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.
50
ES Modules
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
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.
51
ES Modules
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 <script> tag with the special type="module"
attribute:
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:
toUpperCase('test') //'TEST'
You can also use an absolute path for the module import, to reference modules defined on
another domain:
This is not:
52
ES Modules
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 }
You can import just a few of those exports, using the destructuring assignment:
You can import the default export, and any non-default export by name, like in this common
React import:
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: * )
53
ES Modules
Conclusion
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.
54
Single Page Apps
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.
Gmail
Google Maps
Facebook
Twitter
Google Drive
55
Single Page Apps
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.
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).
56
Single Page Apps
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.
57
Declarative
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 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.
58
Immutability
Immutability
What is immutability? And how does it fit in the React world?
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.
Instead of changing an array, to add a new item you create a new array by concatenating the
old array, plus the new item.
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.
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.
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.
59
Immutability
60
Purity
Purity
What is purity, a pure function and a pure component
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.
Class components can be pure if their output only depends on the props:
61
Composition
Composition
What is composition and why is it a key concept in your React apps
For example, think about using map() to create a new array from an initial set, and then
filtering the result using filter() :
You create small and lean components and use them to compose more functionality on top of
them. How?
62
Composition
Using children
The props.children property allows you to inject components inside other components.
<Sidebar>
<Link title="First link" />
<Link title="Second link" />
</Sidebar>
63
The Virtual DOM
Many existing frameworks, before React came on the scene, were directly manipulating the
DOM on every change.
The DOM (Document Object Model) is a Tree representation of the page, starting from the
<html> 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
React uses a Virtual DOM to help the browser use less resources when changes need to be
done on a page.
64
The Virtual DOM
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.
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
65
Unidirectional Data Flow
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.
The view is a result of the application state. State can only change when actions happen.
When actions happen, the state is updated.
66
Unidirectional Data Flow
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.
67
JSX
JSX
JSX is a technology that was introduced by React. Let's dive into it
Introduction to 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:
68
JSX
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.
You just need to pay attention when an attribute has a dash ( - ) which is converted to
camelCase syntax instead, and these 2 special cases:
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.
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.
69
JSX
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.
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:
70
JSX
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.
<p class="description">
<p className="description">
71
JSX
Forms
Form fields definition and events are changed in JSX to provide more consistency and utility.
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'
}
or
The CSS values you write in JSX are slightly different from plain CSS:
72
JSX
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.
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.
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
<textarea>Some text</textarea>
but instead
<select>
73
JSX
use
<select defaultValue="x">
<option value="x">...</option>
</select>
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.
This means that you might run into issues when using an HTML entity in a string expression.
<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>
74
JSX
becomes
<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>
<p>
Something
{' becomes '}
this
</p>
75
JSX
<p>
{/* a comment */}
{
//another comment
}
</p>
Spread attributes
In JSX a common operation is assigning values to attributes.
<div>
<BlogPost title={data.title} date={data.date} />
</div>
<div>
<BlogPost {...data} />
</div>
and the properties of the data object will be used as attributes automatically, thanks to the
ES6 spread operator
const items = []
76
JSX
Now when rendering the JSX you can embed the items array simply by wrapping it in curly
braces:
const items = []
return (
<div>
{items}
</div>
)
You can do the same directly in the JSX, using map instead of a for-of loop:
77
Components
Components
A brief introduction to React 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.
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 .
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:
78
Components
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:
A class component:
79
Components
</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:
React.createClass({
render() {
return (
<div>
<h1>Title</h1>
<p>Description</p>
</div>
)
}
})
80
State
State
How to interact with the state of your components
render() {
return (
<div>
<h1>Title</h1>
<p>Description</p>
</div>
)
}
}
render() {
return (
<div>
<h1>Title</h1>
<p>Description</p>
<p>Clicked: {this.state.clicked}</p>
</div>
)
}
}
81
State
this.state.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.
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.
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:
82
State
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:
render() {
return (
<div>
<Display currency={this.state.currency} />
<CurrencySwitcher
currency={this.state.currency}
handleChangeCurrency={this.handleChangeCurrency}
/>
</div>
)
}
}
83
State
84
Props
Props
How to use props to pass data around your React components
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:
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.
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.
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.
85
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.
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:
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.
86
Props
87
Presentational vs container components
In React components are often divided into 2 big buckets: presentational components and
container components.
They don't manage any kind of state, except for state related the the presentation
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:
On the other hand this is a container component. It manages and stores its own data, and
uses the presentational component to display it.
componentDidMount() {
axios.get('/users').then(users =>
this.setState({ users: users }))
)
}
88
Presentational vs container components
render() {
return <Users users={this.state.users} />
}
}
89
State vs Props
State vs Props
What's the difference between state and props in React?
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.
<ChildComponent />
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:
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.
90
State vs Props
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 to have 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.
91
PropTypes
PropTypes
How to use PropTypes to set the required type of a prop
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:
BlogPostExcerpt.propTypes = {
title: PropTypes.string,
description: PropTypes.string
}
PropTypes.array
PropTypes.bool
PropTypes.func
PropTypes.number
PropTypes.object
PropTypes.string
PropTypes.symbol
92
PropTypes
PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]),
PropTypes.oneOf(['Test1', 'Test2']),
PropTypes.instanceOf(Something)
PropTypes.node
PropTypes.any
Arrays have a special syntax that we can use to accept an array of a particular type:
PropTypes.arrayOf(PropTypes.string)
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,
93
PropTypes
94
Fragment
Fragment
How to use React.Fragment to create invisible HTML tags
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 :
which also has a very nice shorthand syntax <></> that is supported only in recent releases
(and Babel 7+):
95
Events
Events
Learn how to interact with events in a React application
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:
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:
All handlers receive an event object that adheres, cross-browser, to the W3C UI Events spec.
96
Events
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:
Clipboard
onCopy
onCut
onPaste
Composition
onCompositionEnd
onCompositionStart
onCompositionUpdate
Keyboard
onKeyDown
onKeyPress
onKeyUp
Focus
onFocus
97
Events
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
98
Events
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
99
Events
onAnimationIteration
Transition
onTransitionEnd
100
Lifecycle events
Lifecycle events
Find out the React Lifecycle events and how you can use them
React class components can have hooks for several lifecycle events.
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.
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'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.
101
Lifecycle events
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.
shouldComponentUpdate()
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.
getSnapshotBeforeUpdate()
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.
102
Lifecycle events
componentDidUpdate()
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.
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.
103
Handling forms
Handling forms
How to handle forms in a React application
Forms are one of the few HTML elements that are interactive by default.
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.
104
Handling forms
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.
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:
handleChange(event) {
this.setState({ value: event.target.value })
}
render() {
return (
<form>
<input
type="text"
value={this.state.username}
onChange={this.handleChange}
105
Handling forms
/>
</form>
)
}
}
Similarly, we use the onSubmit attribute on the form to call the handleSubmit method when
the form is submitted:
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.
106
Handling forms
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:
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 (Formik tutorial coming tomorrow!)
107
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:
button refers to a property of the component, which can then be used by the component's
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)} />
}
108
Reference a DOM element
109
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.
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.
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
To understand how SSR works, let's start from the basics to implement a proof of concept.
110
Server side rendering
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
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 .
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.
111
Server side rendering
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' })
)
// app.use(express.static('./build'))
app.listen(PORT, () => {
console.log(`SSR running on port ${PORT}`)
})
call ReactDOM.hydrate() , which is the same but has the additional ability to attach event
listeners to existing markup once React loads:
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).
ignore-styles is a Babel utility that will tell it to ignore CSS files imported using the import
syntax.
require('ignore-styles')
112
Server side rendering
require('@babel/register')({
ignore: [/(node_modules)/],
presets: ['@babel/preset-env', '@babel/preset-react']
})
require('./server')
node server/index.js
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)
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.
In particular, I suggest Next.js and Gatsby, two projects we'll see later on.
113
Context API
Context API
The Context API is a neat way to pass state across the app without having to
use props
The Context API 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.
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:
render() {
return (
<Provider value={{ state: this.state }}>{this.props.children}</Provider>
)
}
}
114
Context API
I used Container as the name of this component because this will be a global provider. You
can also create smaller contexts.
Inside a component that's wrapped in a Provider, you use a Consumer component to make
use of the context:
You can also pass functions into a Provider value, and those functions will be used by the
Consumer to update the context state:
<Provider value={{
state: this.state,
updateSomething: () => this.setState({something: 'ho!'})
{this.props.children}
</Provider>
/* ... */
<Consumer>
{(context) => (
<button onClick={context.updateSomething}>{context.state.something}</button>
)}
</Consumer>
You can create multiple contexts, to make your state distributed across components, yet
expose it and make it reachable by any component you want.
When using multiple files, you create the content in one file, and import it in all the places you
use it:
//context.js
import React from 'react'
export default React.createContext()
//component1.js
import Context from './context'
//... use Context.Provider
//component2.js
import Context from './context'
115
Context API
116
Higher-order components
Higher-order components
Find out what Higher Order Components are and how they are useful when
programming a React application
You might be familiar with Higher Order Functions in JavaScript. Those are functions that
accept functions as arguments, and/or return functions.
In general, higher order components allow you to create code that's composable and reusable,
and also more encapsulated.
We can use a HOC to add methods or properties to the state of a component, or a Redux
store for example.
You might want to use Higher Order Components when you want to enhance an existing
component, operate on the state or props, or its rendered markup.
There is a convention of prepending a Higher Order Component with the with string (it's a
convention, so it's not mandatory), so if you have a Button component, its HOC counterpart
should be called withButton .
The simplest example ever of a HOC is one that simply returns the component unaltered:
Let's make this a little bit more useful and add a property to that button, in addition to all the
props it already came with, the color:
const withButton = Element => props => <Button {...props} color="red" />
117
Higher-order components
and we can finally render the WrappedButton component in our app JSX:
function App() {
return (
<div className="App">
<h1>Hello</h1>
<WrappedButton />
</div>
)
}
This is a very simple example but hopefully you can get the gist of HOCs before applying
those concepts to more complex scenarios.
118
Render Props
Render Props
Learn how Render Props can help you build a React application
A common pattern used to share state between components is to use the children prop.
Inside a component JSX you can render {this.props.children} which automatically injects
any JSX passed in the parent component as a children:
render() {
return <div>{this.props.children}</div>
}
}
However, there is a problem here: the state of the parent component cannot be accessed from
the children.
To be able to share the state, you need to use a render prop component, and instead of
passing components as children of the parent component, you pass a function which you then
execute in {this.props.children()} . The function can accept arguments, :
render() {
return <div>{this.props.children(this.state.name)}</div>
}
}
119
Render Props
Instead of using the children prop, which has a very specific meaning, you can use any prop,
and so you can use this pattern multiple times on the same component:
render() {
return (
<div>
<p>Test</p>
{this.props.someprop1(this.state.name)}
{this.props.someprop2(this.state.age)}
</div>
)
}
}
120
Hooks
Hooks
Learn how Hooks can help you build a React application
Hooks is a feature that will be introduced in React 16.7, and is going to change how we write
React apps in the future.
Before Hooks appeared, some key things in components were only possible using class
components: having their own state, and using lifecycle events. Function components, lighter
and more flexible, were limited in functionality.
Hooks allow function components to have state and to respond to lifecycle events too,
and kind of make class components obsolete. They also allow function components to have a
good way to handle events.
Access state
Using the useState() API, you can create a new state variable, and have a way to alter it.
useState() accepts the initial value of the state item and returns an array containing the state
variable, and the function you call to alter the state. Since it returns an array we use array
destructuring to access each individual item, like this: const [count, setCount] = useState(0)
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
)
}
You can add as many useState() calls you want, to create as many state variables as you
want. Just make sure you call it in the top level of a component (not in an if or in any other
block).
Example on Codepen:
121
Hooks
See the Pen React Hooks example #1 counter by Flavio Copes (@flaviocopes) on CodePen.
Hooks provide the useEffect() API. The call accepts a function as argument.
The function runs when the component is first rendered, and on every subsequent re-
render/update. React first updates the DOM, then calls any function passed to useEffect() .
All without blocking the UI rendering even on blocking code, unlike the old componentDidMount
and componentDidUpdate , which makes our apps feel faster.
Example:
useEffect(() => {
console.log(`Hi ${name} you clicked ${count} times`)
})
return (
<div>
<p>
Hi {name} you clicked {count} times
</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
<button onClick={() => setName(name === 'Flavio' ? 'Roger' : 'Flavio')}>
Change name
</button>
</div>
)
}
ReactDOM.render(
<CounterWithNameAndSideEffect />,
document.getElementById('app')
)
122
Hooks
The same componentWillUnmount job can be achieved by optionally returning a function from
our useEffect() parameter:
useEffect(() => {
console.log(`Hi ${name} you clicked ${count} times`)
return () => {
console.log(`Unmounted`)
}
})
useEffect() can be called multiple times, which is nice to separate unrelated logic (something
Since the useEffect() functions are run on every subsequent re-render/update, we can tell
React to skip a run, for performance purposes, by adding a second parameter which is an
array that contains a list of state variables to watch for. React will only re-run the side effect if
one of the items in this array changes.
useEffect(
() => {
console.log(`Hi ${name} you clicked ${count} times`)
},
[name, count]
)
Similarly you can tell React to only execute the side effect once (at mount time), by passing an
empty array:
useEffect(() => {
console.log(`Component mounted`)
}, [])
useEffect() is great for adding logs, accessing 3rd party APIs and much more.
Example on Codepen:
See the Pen React Hooks example #3 side effects by Flavio Copes (@flaviocopes) on
CodePen.
123
Hooks
Any parameter used inside the function must be passed through a second parameter to
useCallback() , in an array:
Using custom hooks you have one more way to share state and logic between components,
adding a significant improvement to the patterns of render props and higher order
components. Which are still great, but now with custom hooks have less relevance in many
use cases.
A hook is just a function that conventionally starts with use . It can accept an arbitrary number
of arguments, and return anything it wants.
Examples:
const useGetData() {
//...
return data
}
or
124
Hooks
const useGetUser(username) {
//...const user = fetch(...)
//...const userData = ...
return [user, userData]
}
In your own components, you can use the hook like this:
When exactly to add hooks instead of regular functions should be determined on a use case
basis, and only experience will tell.
125
Code splitting
Code splitting
What is Code Splitting and how to introduce it in a React app
Modern JavaScript applications can be quite huge in terms of bundle size. You don't want your
users to have to download a 1MB package of JavaScript (your code and the libraries you use)
just to load the first page, right? But this is what happens by default when you ship a modern
Web App built with Webpack bundling.
That bundle will contain code that might never run because the user only stops on the login
page and never sees the rest of your app.
Code splitting is the practice of only loading the JavaScript you need the moment when you
need it.
This improves:
React 16.6.0, released in October 2018, introduced a way of performing code splitting that
should take the place of every previously used tool or library: React.lazy and Suspense.
React.lazy and Suspense form the perfect way to lazily load a dependency and only load it
when needed.
the TodoList component will be dynamically added to the output as soon as it's available.
Webpack will create a separate bundle for it, and will take care of loading it when necessary.
Suspense is a component that you can use to wrap any lazily loaded component:
126
Code splitting
It takes care of handling the output while the lazy loaded component is fetched and rendered.
...
<React.Suspense fallback={<p>Please wait</p>}>
<TodoList />
</React.Suspense>
...
127
Build a simple counter
In this short tutorial we'll build a very simple example of a counter in React, applying many of
the concepts and theory outlined before.
Let's use Codepen for this. We start by forking the React template pen.
In Codepen we don't need to import React and ReactDOM as they are already added in
the scope.
We show the count in a div, and we add a few buttons to increment this count:
return (
<div>
<Button increment={1} />
<Button increment={10} />
<Button increment={100} />
<Button increment={1000} />
<span>{count}</span>
</div>
)
}
Let's add the functionality that lets us change the count by clicking the buttons, by adding a
onClickFunction prop:
128
Build a simple counter
return (
<div>
<Button increment={1} onClickFunction={incrementCount} />
<Button increment={10} onClickFunction={incrementCount} />
<Button increment={100} onClickFunction={incrementCount} />
<Button increment={1000} onClickFunction={incrementCount} />
<span>{count}</span>
</div>
)
}
Here, every Button element has 2 props: increment and onClickFunction . We create 4
different buttons, with 4 increment values: 1, 10 100, 1000.
When the button in the Button component is clicked, the incrementCount function is called.
This function must increment the local count. How can we do so? We can use hooks:
return (
<div>
<Button increment={1} onClickFunction={incrementCount} />
<Button increment={10} onClickFunction={incrementCount} />
<Button increment={100} onClickFunction={incrementCount} />
<Button increment={1000} onClickFunction={incrementCount} />
<span>{count}</span>
</div>
)
}
useState() initializes the count variable at 0 and provides us the setCount() method to
129
Build a simple counter
130
Fetch and display GitHub users information via API
Very simple example of a form that accepts a GitHub username and once it receives a
submit event, it asks the GitHub API for the user information, and prints them.
This code creates a reusable Card component. When you enter a name in the input field
managed by the Form component, this name is bound to its state.
When Add card is pressed, the input form is cleared by clearing the userName state of the
Form component.
The example uses, in addition to React, the Axios library. It's a nice useful and lightweight
library to handle network requests. Add it to the Pen settings in Codepen, or install it locally
using npm install axios .
131
Fetch and display GitHub users information via API
Output
Code
132
Fetch and display GitHub users information via API
We start by creating the Card component, the one that will display our image and details as
gathered from GitHub. It gets its data via props, using
We create a list of those components, which will be passed by a parent component in the
cards prop to CardList , which simply iterates on it using map() and outputs a list of cards:
The parent component is App, which stores the cards array in its own state, managed using
the useState() Hook:
return (
<div>
<CardList cards={cards} />
</div>
)
}
Cool! We must have a way now to ask GitHub for the details of a single username. We'll do so
using a Form component, where we manage our own state ( username ), and we ask GitHub
for information about a user using their public APIs, via Axios:
133
Fetch and display GitHub users information via API
axios.get(`https://api.github.com/users/${username}`).then(resp => {
props.onSubmit(resp.data)
setUsername('')
})
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={username}
onChange={event => setUsername(event.target.value)}
placeholder="GitHub username"
required
/>
<button type="submit">Add card</button>
</form>
)
}
When the form is submitted we call the handleSubmit event, and after the network call we call
props.onSubmit passing the parent ( App ) the data we got from GitHub.
We add it to App , passing a method to add a new card to the list of cards, addNewCard , as its
onSubmit prop:
return (
<div>
<Form onSubmit={addNewCard} />
<CardList cards={cards} />
</div>
)
}
134
Fetch and display GitHub users information via API
axios
.get(`https://api.github.com/users/${username}`)
.then(resp => {
props.onSubmit(resp.data)
setUsername('')
})
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={username}
onChange={event => setUsername(event.target.value)}
placeholder="GitHub username"
required
/>
<button type="submit">Add card</button>
</form>
)
}
return (
<div>
<Form onSubmit={addNewCard} />
<CardList cards={cards} />
</div>
135
Fetch and display GitHub users information via API
)
}
136
CSS in React
CSS in React
How to use CSS to style a React application
Using React you have various ways to add styling to your components.
.button {
background-color: yellow;
}
You can import the stylesheet using an import statement, like this:
import './style.css'
and Webpack will take care of adding the CSS property to the bundle.
CSS is defined in a slightly different way now. First, notice the double curly brackets: it's
because style accepts an object. We pass in a JavaScript object, which is defined in curly
braces. We could also do this:
137
CSS in React
When using create-react-app , those styles are autoprefixed by default thanks to its use of
Autoprefixer.
Also, the style now is camelCased instead of using dashes. Every time a CSS property has a
dash, remove it and start the next word capitalized.
Styles have the benefit of being local to the component, and they cannot leak to other
components in other parts of the app, something that using classes and an external CSS file
can't provide.
Start by creating a CSS file that ends with .module.css , for example Button.module.css . A
great choice is to give it the same name as the component you are going to style
Add your CSS here, then import it inside the component file you want to style:
That's it! In the resulting markup, React will generate a specific, unique class for each
rendered component, and assign the CSS to that class, so that the CSS is not affecting other
markup.
138
CSS in React
139
SASS with React
When you build a React application using create-react-app , you have many options at your
disposal when it comes to styling.
Of course, if not using create-react-app , you have all the choices in the world, but we
limit the discussion to the create-react-app -provided options.
You can style using plain classes and CSS files, using the style attribute or CSS Modules, to
start with.
You can use it without any configuration at all, starting with create-react-app 2.
All you need is a .sass or .scss file, and you just import it in a component:
import './styles.scss'
140
SASS with React
141
Styled Components
Styled Components
Styled Components are one of the new ways to use CSS in modern
JavaScript. It is the meant to be a successor of CSS Modules, a way to write
CSS that's scoped to a single component, and not leak to any other element
in the page
A brief history
Once upon a time, the Web was really simple and CSS didn't even exist. We laid out pages
using tables and frames. Good times.
Then CSS came to life, and after some time it became clear that frameworks could greatly
help especially in building grids and layouts, Bootstrap and Foundation playing a big part in
this.
Preprocessors like SASS and others helped a lot to slow down the adoption of frameworks,
and to better organize the code, conventions like BEM and SMACSS grew in use, especially
within teams.
Conventions are not a solution to everything, and they are complex to remember, so in the last
few years with the increasing adoption of JavaScript and build processes in every frontend
project, CSS found its way into JavaScript (CSS-in-JS).
New tools explored new ways of doing CSS-in-JS and a few succeeded with increasing
popularity:
React Style
jsxstyle
Radium
and more.
It is the meant to be a successor to CSS Modules, a way to write CSS that's scoped to a
single component, and not leak to any other element in the page.
142
Styled Components
Styled Components allow you to write plain CSS in your components without worrying about
class name collisions.
Installation
Simply install styled-components using npm or yarn:
We created it using a function of the styled object, called button in this case, and passing
some CSS properties in a template literal.
Now this component can be rendered in our container using the normal React syntax:
render(<Button />)
Styled Components offer other functions you can use to create other components, not just
button , like section , h1 , input and many others.
The syntax used, with the backtick, might be weird at first, but it's called Tagged Templates,
it's plain JavaScript and it's a way to pass an argument to the function.
143
Styled Components
When you pass some props to a Styled Component, it will pass them down to the DOM node
mounted.
For example here's how we pass the placeholder and type props to an input component:
render(
<div>
<Input placeholder="..." type="text" />
</div>
)
This will do just what you think, inserting those props as HTML attributes.
Props instead of just being blindly passed down to the DOM can also be used to customize a
component based on the prop value. Here's an example:
render(
<div>
<Button>A normal button</Button>
<Button>A normal button</Button>
<Button primary>The primary button</Button>
</div>
)
144
Styled Components
render(
<div>
<Button>A black button, like all buttons</Button>
<WhiteButton>A white button</WhiteButton>
</div>
)
You can use media queries, nesting and anything else you might need.
Conclusion
That's it for this Styled Components introduction! These concepts will help you get an
understanding of the concept and help you get up and running with this way of using CSS in
JavaScript.
145
Babel
Babel
Babel is an awesome entry in the Web Developer toolset. It's an awesome
tool, and it’s been around for quite some time, but nowadays almost every
JavaScript developer relies on it, and this will continue going on, because
Babel is now indispensable and has solved a big problem for everyone.
Babel is an awesome tool, and it’s been around for quite some time, but nowadays almost
every JavaScript developer relies on it, and this will continue, because Babel is now
indispensable and has solved a big problem for everyone.
Which problem?
The problem that every Web Developer has surely had: a feature of JavaScript is available in
the latest release of a browser, but not in the older versions. Or maybe Chrome or Firefox
implement it, but Safari iOS and Edge do not.
Which is now supported by all modern browsers. IE11 does not support it, nor Opera Mini
(How do I know? By checking the ES6 Compatibility Table).
So how should you deal with this problem? Should you move on and leave those customers
with older/incompatible browsers behind, or should you write older JavaScript code to make all
your users happy?
Enter Babel. Babel is a compiler: it takes code written in one standard, and it transpiles it to
code written into another standard.
You can configure Babel to transpile modern ES2017 JavaScript into JavaScript ES5 syntax:
[1, 2, 3].map(function(n) {
return n + 1
})
This must happen at build time, so you must setup a workflow that handles this for you.
Webpack is a common solution.
(P.S. if all this ES thing sounds confusing to you, see more about ES versions in the
ECMAScript guide)
146
Babel
Installing Babel
Babel is easily installed using npm, locally in a project:
In the past I recommended installing babel-cli globally, but this is now discouraged by
the Babel maintainers, because by using it locally you can have different versions of
Babel in each project, and also checking in babel in your repository is better for team
work
Since npm now comes with npx , locally installed CLI packages can run by typing the
command in the project folder:
To solve the problem we talked about in the introduction (using arrow functions in every
browser), we can run
to download the package in the node_modules folder of our app, then we need to add
{
"plugins": ["transform-es2015-arrow-functions"]
}
to the .babelrc file present in the application root folder. If you don't have that file already,
you just create a blank file, and put that content into it.
TIP: If you have never seen a dot file (a file starting with a dot) it might be odd at first
because that file might not appear in your file manager, as it's a hidden file.
147
Babel
var bob = {
_name: "Bob",
_friends: ["Sally", "Tom"],
printFriends() {
this._friends.forEach(f =>
console.log(this._name + " knows " + f));
}
};
console.log(bob.printFriends());
var bob = {
_name: "Bob",
_friends: ["Sally", "Tom"],
printFriends() {
var _this = this;
this._friends.forEach(function (f) {
return console.log(_this._name + " knows " + f);
});
}
};
console.log(bob.printFriends());
As you can see arrow functions have all been converted to JavaScript ES5 functions.
Babel presets
We just saw in the previous article how Babel can be configured to transpile specific
JavaScript features.
You can add much more plugins, but you can't add to the configuration features one by one,
it's not practical.
148
Babel
Tip: Babel 7 deprecated (and removed) yearly presets like preset-es2017 , and stage
presets. Use @babel/preset-env instead.
env preset
The env preset is very nice: you tell it which environments you want to support, and it does
everything for you, supporting all modern JavaScript features.
E.g. "support the last 2 versions of every browser, but for Safari let's support all versions since
Safari 7`
{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "safari >= 7"]
}
}]
]
}
or "I don't need browser support, just let me work with Node.js 6.10"
{
"presets": [
["env", {
"targets": {
"node": "6.10"
}
}]
]
}
react preset
The react preset is very convenient when writing React apps: adding preset-flow , syntax-
jsx , transform-react-jsx , transform-react-display-name .
By including it, you are all ready to go developing React apps, with JSX transforms and Flow
support.
149
Babel
https://babeljs.io/docs/plugins/
TIP: read the webpack guide if you're not familiar with webpack
Modern JS needs two different stages: a compile stage, and a runtime stage. This is because
some ES6+ features need a polyfill or a runtime helper.
entry: [
'babel-polyfill',
// your app scripts should be here
],
module: {
loaders: [
// Babel loader compiles ES2015 into ES5 for
// complete cross-browser support
{
loader: 'babel-loader',
test: /\.js$/,
// only include files present in the `src` subdirectory
include: [path.resolve(__dirname, "src")],
// exclude node_modules, equivalent to the above line
exclude: /node_modules/,
query: {
// Use the default ES2015 preset
// to include all ES2015 features
presets: ['es2015'],
plugins: ['transform-runtime']
}
}
]
}
By keeping the presets and plugins information inside the webpack.config.js file, we can
avoid having a .babelrc file.
150
Babel
151
Webpack
Webpack
Webpack is a tool that has got a lot of attention in the last few years, and it is
now seen used in almost every project. Learn about it.
What is webpack?
Webpack is a tool that lets you compile JavaScript modules, also known as module bundler.
Given a large number of files, it generates a single file (or a few files) that run your app.
152
Webpack
Webpack is not limited to be use on the frontend, it's also useful in backend Node.js
development as well.
Grunt
Broccoli
Gulp
There are lots of similarities in what those and Webpack can do, but the main difference is that
those are known as task runners, while webpack was born as a module bundler.
It's a more focused tool: you specify an entry point to your app (it could even be an HTML file
with script tags) and webpack analyzes the files and bundles all you need to run the app in a
single JavaScript output file (or in more files if you use code splitting).
Installing webpack
Webpack can be installed globally or locally for each project.
Global install
Here's how to install it globally with Yarn:
with npm:
webpack-cli
153
Webpack
Local install
Webpack can be installed locally as well. It's the recommended setup, because webpack can
be updated per-project, and you have less resistance to using the latest features just for a
small project rather than updating all the projects you have that use webpack.
With Yarn:
with npm:
{
//...
"scripts": {
"build": "webpack"
}
}
154
Webpack
yarn build
Webpack configuration
By default, webpack (starting from version 4) does not require any config if you respect these
conventions:
You can customize every little bit of webpack of course, when you need. The webpack
configuration is stored in the webpack.config.js file, in the project root folder.
module.exports = {
/*...*/
entry: './index.js'
/*...*/
}
The output
By default the output is generated in ./dist/main.js . This example puts the output bundle
into app.js :
module.exports = {
/*...*/
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js'
}
/*...*/
}
155
Webpack
Loaders
Using webpack allows you to use import or require statements in your JavaScript code to
not just include other JavaScript, but any kind of file, for example CSS.
Webpack aims to handle all our dependencies, not just JavaScript, and loaders are one way to
do that.
import 'style.css'
module.exports = {
/*...*/
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
}]
}
/*...*/
}
module.exports = {
/*...*/
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
/*...*/
}
156
Webpack
module.exports = {
/*...*/
module: {
rules: [
{
test: /\.css$/,
use:
[
'style-loader',
'css-loader',
]
}
]
}
/*...*/
}
In this example, css-loader interprets the import 'style.css' directive in the CSS. style-
loader is then responsible for injecting that CSS in the DOM, using a <style> tag.
The order matters, and it's reversed (the last is executed first).
What kind of loaders are there? Many! You can find the full list here.
A commonly used loader is Babel, which is used to transpile modern JavaScript to ES5 code:
module.exports = {
/*...*/
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
/*...*/
}
module.exports = {
/*...*/
module: {
rules: [
{
157
Webpack
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: 'babel-loader'
}
]
},
resolve: {
extensions: [
'.js',
'.jsx'
]
}
/*...*/
}
Plugins
Plugins are like loaders, but on steroids. They can do things that loaders can't do, and they are
the main building block of webpack.
module.exports = {
/*...*/
plugins: [
new HTMLWebpackPlugin()
]
/*...*/
}
The HTMLWebpackPlugin plugin has the job of automatically creating an HTML file, adding the
output JS bundle path, so the JavaScript is ready to be served.
One useful plugin, CleanWebpackPlugin , can be used to clear the dist/ folder before creating
any output, so you don't leave files around when you change the name of the output file:
module.exports = {
/*...*/
plugins: [
new CleanWebpackPlugin(['dist']),
]
/*...*/
}
158
Webpack
module.exports = {
entry: './index.js',
mode: 'development',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js'
}
}
Development mode:
Production mode is slower to build, since it needs to generate a more optimized bundle. The
resulting JavaScript file is smaller in size, as it removes many things that are not needed in
production.
159
Webpack
160
Webpack
Running webpack
Webpack can be run from the command line manually if installed globally, but generally you
write a script inside the package.json file, which is then run using npm or yarn .
"scripts": {
"build": "webpack"
}
or
161
Webpack
or simply
yarn build
Watching changes
Webpack can automatically rebuild the bundle when a change in your app happens, and keep
listening for the next change.
"scripts": {
"watch": "webpack --watch"
}
and run
or
or simply
yarn watch
One nice feature of the watch mode is that the bundle is only changed if the build has no
errors. If there are errors, watch will keep listening for changes, and try to rebuild the bundle,
but the current, working bundle is not affected by those problematic builds.
Handling images
Webpack allows us to use images in a very convenient way, using the file-loader loader.
module.exports = {
/*...*/
module: {
rules: [
162
Webpack
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
/*...*/
}
file-loader can handle other asset types as well, like fonts, CSV files, xml, and more.
This example loads any PNG file smaller than 8KB as a data URL.
module.exports = {
/*...*/
module: {
rules: [
{
test: /\.png$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
}
/*...*/
}
163
Webpack
module.exports = {
/*...*/
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
]
}
/*...*/
}
You tell webpack to generate source maps using the devtool property of the configuration:
module.exports = {
/*...*/
devtool: 'inline-source-map',
/*...*/
}
devtool has many possible values, the most used probably are:
source-map : ideal for production, provides a separate source map that can be minimized,
and adds a reference into the bundle, so development tools know that the source map is
available. Of course you should configure the server to avoid shipping this, and just use it
for debugging purposes
inline-source-map : ideal for development, inlines the source map as a Data URL
164
Prettier
Prettier
Prettier is an opinionated code formatter. It is a great way to keep code
formatted consistently for you and your team, and supports a lot of different
languages out of the box
JavaScript
165
Prettier
Flow, TypeScript
CSS, SCSS, Less
JSX
GraphQL
JSON
Markdown
and with plugins you can use it for Python, PHP, Swift, Ruby, Java and more.
It integrates with the most popular code editors, including VS Code, Sublime Text, Atom and
more.
Prettier is hugely popular, as in February 2018 it has been downloaded over 3.5 million times.
The most important links you need to know more about Prettier are
https://prettier.io/
https://github.com/prettier/prettier
https://www.npmjs.com/package/prettier
Less options
I learned Go recently and one of the best things about Go is gofmt, an official tool that
automatically formats your code according to common standards.
95% (made up stat) of the Go code around looks exactly the same, because this tool can be
easily enforced and since the style is defined for you by the Go maintainers, you are much
more likely to adapt to that standard instead of insisting on your own style. Like tabs vs
spaces, or where to put an opening bracket.
This might sound like a limitation, but it's actually very powerful. All Go code looks the same.
It has very few options, and most of the decisions are already taken for you so you can
stop arguing about style and little things, and focus on your code.
166
Prettier
ESLint also highlights formatting issues, but since it's a lot more configurable, everyone could
have a different set of formatting rules. Prettier provides a common ground for all.
and some others, but Prettier tries to keep the number of those customizations under control,
to avoid becoming too customizable.
Installation
Prettier can run from the command line, and you can install it using Yarn or npm.
Another great use case for Prettier is to run it on PRs for your Git repositories, for example on
GitHub.
If you use a supported editor the best thing is to use Prettier directly from the editor, and the
Prettier formatting will be run every time you save.
Formatting is a topic that's mostly overlooked by beginners, but having clean and consistent
formatting is key to your success as a new developer.
Also, even if you started using JavaScript 2 weeks ago, with Prettier your code - style wise -
will look just like code written from a JavaScript Guru writing JS since 1998.
167
Introduction to Jest
Introduction to Jest
Jest is a library for testing JavaScript code. It's an open source project
maintained by Facebook, and it's especially well suited for React code
testing, although not limited to that: it can test any JavaScript code. Jest is
very fast and easy to use
It's an open source project maintained by Facebook, and it's especially well suited for React
code testing, although not limited to that: it can test any JavaScript code. Its strengths are:
it's fast
it can perform snapshot testing
it's opinionated, and provides everything out of the box without requiring you to make
choices
168
Introduction to Jest
In my opinion the biggest feature of Jest is it's an out of the box solution that works without
having to interact with other testing libraries to perform its job.
Installation
Jest is automatically installed in create-react-app , so if you use that, you don't need to install
Jest.
or npm:
notice how we instruct both to put Jest in the devDependencies part of the package.json file, so
that it will only be installed in the development environment and not in production.
{
"scripts": {
"test": "jest"
}
}
so that tests can be run using yarn test or npm run test .
and run all your tests using the jest command line tool.
169
Introduction to Jest
{
"scripts": {
"test": "jest"
}
}
Now, you don't have any tests here, so nothing is going to be executed:
Let's create the first test. Open a math.js file and type a couple functions that we'll later test:
Now create a math.test.js file, in the same folder, and there we'll use Jest to test the
functions defined in math.js :
170
Introduction to Jest
Running yarn test results in Jest being run on all the test files it finds, and returning us the
end result:
Once you install it, it will automatically detect if you have installed Jest in your
devDependencies and run the tests. You can also invoke the tests manually by selecting the
Jest: Start Runner command. It will run the tests and stay in watch mode to re-run them
whenever you change one of the files that have a test (or a test file):
171
Introduction to Jest
Matchers
In the previous article I used toBe() as the only matcher:
Most commonly used matchers, comparing the value of the result of expect() with the value
passed in as argument, are:
toEqual compares the values of two variables. If it's an object or array, it checks the
172
Introduction to Jest
toBeLessThanOrEqual true if the result of expect() is equal to the argument, or lower than
the argument
toMatch is used to compare strings with regular expression pattern matching
toContain is used in arrays, true if the expected array contains the argument in its
elements set
toHaveLength(number) : checks the length of an array
toHaveProperty(key, value) : checks if an object has a property, and optionally checks its
value
toThrow checks if a function you pass throws an exception (in general) or a specific
exception
toBeInstanceOf() : checks if an object is an instance of a class
All those matchers can be negated using .not. inside the statement, for example:
For use with promises, you can use .resolves and .rejects :
expect(Promise.resolve('lemon')).resolves.toBe('lemon')
expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus')
Setup
Before running your tests you will want to perform some initialization.
To do something once before all the tests run, use the beforeAll() function:
beforeAll(() => {
//do something
})
173
Introduction to Jest
beforeEach(() => {
//do something
})
Teardown
Just as you can do with setup, you can also perform something after each test runs:
afterEach(() => {
//do something
})
afterAll(() => {
//do something
})
174
Introduction to Jest
Callbacks
You can't have a test in a callback, because Jest won't execute it - the execution of the test file
ends before the callback is called. To fix this, pass a parameter to the test function, which you
can conveniently call done . Jest will wait until you call done() before ending that test:
//uppercase.js
function uppercase(str, callback) {
callback(str.toUpperCase())
}
module.exports = uppercase
//uppercase.test.js
const uppercase = require('./src/uppercase')
175
Introduction to Jest
Promises
With functions that return promises, we simply return a promise from the test:
//uppercase.js
const uppercase = str => {
return new Promise((resolve, reject) => {
if (!str) {
reject('Empty string')
return
}
resolve(str.toUpperCase())
})
}
module.exports = uppercase
//uppercase.test.js
const uppercase = require('./uppercase')
test(`uppercase 'test' to equal 'TEST'`, () => {
return uppercase('test').then(str => {
expect(str).toBe('TEST')
})
})
176
Introduction to Jest
//uppercase.js
const uppercase = str => {
return new Promise((resolve, reject) => {
if (!str) {
reject('Empty string')
return
}
resolve(str.toUpperCase())
})
}
module.exports = uppercase
//uppercase.test.js
const uppercase = require('./uppercase')
177
Introduction to Jest
Async/await
To test functions that return promises we can also use async/await, which makes the syntax
very straightforward and simple:
//uppercase.test.js
const uppercase = require('./uppercase')
178
Introduction to Jest
Mocking
In testing, mocking allows you to test functionality that depends on:
Database
Network requests
access to Files
any External system
so that:
1. your tests run faster, giving a quick turnaround time during development
179
Introduction to Jest
2. your tests are independent of network conditions, or the state of the database
3. your tests do not pollute any data storage because they do not touch the database
4. any change done in a test does not change the state for subsequent tests, and re-running
the test suite should start from a known and reproducible starting point
5. you don't have to worry about rate limiting on API calls and network requests
Mocking is useful when you want to avoid side effects (e.g. writing to a database) or you want
to skip slow portions of code (like network access), and also avoids implications with running
your tests multiple times (e.g. imagine a function that sends an email or calls a rate-limited
API).
Even more important, if you are writing a Unit Test, you should test the functionality of a
function in isolation, not with all its baggage of things it touches.
Using mocks, you can inspect if a module function has been called and which parameters
were used, with:
called
expect().toHaveBeenCalledWith() : check if the function has been called with a specific set
of parameters
expect().toHaveBeenLastCalledWith() : check the parameters of the last time the function
Example:
expect(mathjs.log).toHaveBeenCalled()
expect(mathjs.log).toHaveBeenCalledWith(10000, 10)
})
180
Introduction to Jest
Jest provides a convenient way to mock an entire package. Create a __mocks__ folder in the
project root, and in this folder create one JavaScript file for each of your packages.
Say you import mathjs . Create a __mocks__/mathjs.js file in your project root, and add this
content:
module.exports = {
log: jest.fn(() => 'test')
}
This will mock the log() function of the package. Add as many functions as you want to mock:
You can also use jest.fn().mockReturnValue('test') to create a simple mock that does
nothing except returning a value.
Pre-built mocks
You can find pre-made mocks for popular libraries. For example this package
https://github.com/jefflau/jest-fetch-mock allows you to mock fetch() calls, and provide
sample return values without interacting with the actual server in your tests.
Snapshot testing
181
Introduction to Jest
Snapshot testing is a pretty cool feature offered by Jest. It can memorize how your UI
components are rendered, and compare it to the current test, raising an error if there's a
mismatch.
This is a simple test on the App component of a simple create-react-app application (make
sure you install react-test-renderer ):
the first time you run this test, Jest saves the snapshot to the __snapshots__ folder. Here's
what App.test.js.snap contains:
182
Introduction to Jest
As you see it's the code that the App component renders, nothing more.
The next time the test compares the output of <App /> to this. If App changes, you get an
error:
When using yarn test in create-react-app you are in watch mode, and from there you can
press w and show more options:
Watch Usage
› Press u to update failing snapshots.
› Press p to filter by a filename regex pattern.
› Press t to filter by a test name regex pattern.
› Press q to quit watch mode.
› Press Enter to trigger a test run.
183
Introduction to Jest
If your change is intended, pressing u will update the failing snapshots, and make the test
pass.
You can also update the snapshot by running jest -u (or jest --updateSnapshot ) outside of
watch mode.
184
Testing React Components
The easiest way to start with testing React components is doing snapshot testing, a testing
technique that lets you test components in isolation.
If you are familiar with testing software, it's just like unit testing you do for classes: you test
each component functionality.
I assume you created a React app with create-react-app , which already comes with Jest
installed, the testing package we'll need.
Let's start with a simple test. CodeSandbox is a great environment to try this out. Start with a
React sandbox, and create an App.js component in a components folder, and add an
App.test.js file.
When CodeSandbox detects test files, it automatically runs them for you, and you can click the
Tests button in the bottom of the view to show your test results:
185
Testing React Components
Let's do something a bit more useful now, to actually test a React component. We only have
App now, which is not doing anything really useful, so let's first set up the environment with a
little application with more functionality: the counter app we built previously. If you skipped it,
you can go back and read how we built it, but for easier reference I add it here again.
186
Testing React Components
It's just 2 components: App and Button. Create the App.js file:
return (
<div>
<Button increment={1} onClickFunction={incrementCount} />
<Button increment={10} onClickFunction={incrementCount} />
<Button increment={100} onClickFunction={incrementCount} />
<Button increment={1000} onClickFunction={incrementCount} />
<span>{count}</span>
</div>
)
}
We are going to use the react-testing-library , which is a great help as it allows us to inspect
the output of every component and to apply events on them. You can read more about it on
https://github.com/kentcdodds/react-testing-library or by watching this video.
We start by importing render and fireEvent from react-testing-library , two helpers. The
first lets us render JSX. The second lets us emit events on a component.
187
Testing React Components
Buttons are used in the app to accept a click event and then they call a function passed to the
onClickFunction prop. We add a count variable and we create a function that increments it:
let count
Now off to the actual tests. We first initialize count to 0, and we render a +1 Button
component passing a 1 to increment and our incrementCount function to onClickFunction .
Then we get the content of the first child of the component, and we check it outputs +1 .
We then proceed to clicking the button, and we check that the count got from 0 to 1:
Similarly we test a +100 button, this time checking the output is +100 and the button click
increments the count of 100.
Let's test the App component now. It shows 4 buttons and the result in the page. We can
inspect each button and see if the result increases when we click them, clicking multiple times
as well:
188
Testing React Components
expect(buttons[0].textContent).toBe('+1')
expect(buttons[1].textContent).toBe('+10')
expect(buttons[2].textContent).toBe('+100')
expect(buttons[3].textContent).toBe('+1000')
189
React Router
React Router
React Router 4 is the perfect tool to link together the URL and your React
app. React Router is the de-facto React routing library, and it's one of the
most popular projects built on top of React.
React Router is the de-facto React routing library, and it's one of the most popular projects
built on top of React.
React at its core is a very simple library, and it does not dictate anything about routing.
Routing in a Single Page Application is the way to introduce some features to navigating the
app through links, which are expected in normal web applications:
1. The browser should change the URL when you navigate to a different screen
2. Deep linking should work: if you point the browser to a URL, the application should
reconstruct the same view that was presented when the URL was generated.
3. The browser back (and forward) button should work like expected.
Routing links together your application navigation with the navigation features offered
by the browser: the address bar and the navigation buttons.
React Router offers a way to write your code so that it will show certain components of
your app only if the route matches what you define.
Installation
190
React Router
With npm:
With Yarn:
Types of routes
React Router provides two different kind of routes:
BrowserRouter
HashRouter
One builds classic URLs, the other builds URLs with the hash:
https://application.com/dashboard /* BrowserRouter */
https://application.com/#/dashboard /* HashRouter */
Which one to use is mainly dictated by the browsers you need to support. BrowserRouter uses
the History API, which is relatively recent, and not supported in IE9 and below. If you don't
have to worry about older browsers, it's the recommended choice.
Components
The 3 components you will interact the most when working with React Router are:
Link
Route
Link components are - as you can imagine - used to generate links to your routes
Route components are responsible for showing - or hiding - the components they contain.
BrowserRouter
191
React Router
Here's a simple example of the BrowserRouter component. You import it from react-router-
dom, and you use it to wrap all your app:
ReactDOM.render(
<Router>
<div>
<!-- -->
</div>
</Router>,
document.getElementById('app')
)
A BrowserRouter component can only have one child element, so we wrap all we're going to
add in a div element.
Link
The Link component is used to trigger new routes. You import it from react-router-dom , and
you can add the Link components to point at different routes, with the to attribute:
ReactDOM.render(
<Router>
<div>
<aside>
<Link to={`/dashboard`}>Dashboard</Link>
<Link to={`/about`}>About</Link>
</aside>
<!-- -->
</div>
</Router>,
document.getElementById('app')
)
Route
Now let's add the Route component in the above snippet to make things actually work as we
want:
192
React Router
ReactDOM.render(
<Router>
<div>
<aside>
<Link to={`/`}>Dashboard</Link>
<Link to={`/about`}>About</Link>
</aside>
<main>
<Route exact path="/" component={Dashboard} />
<Route path="/about" component={About} />
</main>
</div>
</Router>,
document.getElementById('app')
)
When the route matches / , the application shows the Dashboard component.
When the route is changed by clicking the "About" link to /about , the Dashboard component
is removed and the About component is inserted in the DOM.
Notice the exact attribute. Without this, path="/" would also match /about , since / is
contained in the route.
193
React Router
Inline rendering
Instead of specifying a component property on Route , you can set a render prop:
<Route
path="/(about|who)/"
render={() => (
<div>
<h2>About</h2>
...
</div>
)}
/>
//...
//...
In your Route component you can lookup the dynamic parameters in match.params .
194
React Router
match is also available in inline rendered routes, and this is especially useful in this case,
because we can use the id parameter to lookup the post data in our data source before
rendering Post:
const posts = [
{ id: 1, title: 'First', content: 'Hello world!' },
{ id: 2, title: 'Second', content: 'Hello again!' }
]
//...
195
Redux
Redux
Redux is a state manager that's usually used along with React, but it's not
tied to that library. Learn Redux by reading this simple and easy to follow
guide
React has its own way to manage state, as you can read on the React Beginner's Guide,
where I introduce how you can manage State in React.
Moving the state up in the tree works in simple cases, but in a complex app you might find you
are moving almost all the state up, and then down using props.
React in version 16.3.0 introduced the Context API, which makes Redux redundant for the
use case of accessing the state from different parts of your app, so consider using the Context
API instead of Redux, unless you need a specific feature that Redux provides.
Redux is a way to manage an application state, and move it to an external global store.
There are a few concepts to grasp, but once you do, Redux is a very simple approach to the
problem.
Redux is very popular with React applications, but it's in no way unique to React: there are
bindings for nearly any popular framework. That said, I'll make some examples using React as
it is its primary use case.
Simple apps should not need it at all (and there's nothing wrong with simple apps).
196
Redux
In Redux, the whole state of the application is represented by one JavaScript object, called
State or State Tree.
We call it Immutable State Tree because it is read only: it can't be changed directly.
Actions
An Action is a JavaScript object that describes a change in a minimal way (with just the
information needed):
{
type: 'CLICKED_SIDEBAR'
}
The only requirement of an action object is having a type property, whose value is usually a
string.
Action creators
Actions Creators are functions that create actions.
function addItem(t) {
197
Redux
return {
type: ADD_ITEM,
title: t
}
}
You usually run action creators in combination with triggering the dispatcher:
dispatch(addItem('Milk'))
Reducers
When an action is fired, something must happen, the state of the application must change.
What is a reducer
A reducer is a pure function that calculates the next State Tree based on the previous State
Tree, and the action dispatched.
A pure function takes an input and returns an output without changing the input or anything
else. Thus, a reducer returns a completely new state tree object that substitutes the previous
one.
198
Redux
Multiple reducers
Since the state of a complex app could be really wide, there is not a single reducer, but many
reducers for any kind of action.
A simulation of a reducer
At its core, Redux can be simplified with this simple model:
The state
{
list: [
{ title: "First item" },
{ title: "Second item" },
],
title: 'Groceries list'
}
A list of actions
199
Redux
default:
return state
}
}
The Store
The Store is an object that:
store.getState()
200
Redux
store.dispatch(addItem('Something'))
unsubscribe()
Data Flow
Data flow in Redux is always unidirectional.
The Store takes care of passing the Action to the Reducer, generating the next State.
The Store updates the State and alerts all the Listeners.
201
Next.js
Next.js
Next.js is a very popular Node.js framework which enables easy server-side
React rendering, and provides many other amazing features
Working on a modern JavaScript application powered by React is awesome until you realize
that there are a couple problems related to rendering all the content on the client-side.
First, the page takes longer to the become visible to the user, because before the content
loads, all the JavaScript must load, and your application needs to run to determine what to
show on the page.
Second, if you are building a publicly available website, you have a content SEO issue. Search
engines are getting better at running and indexing JavaScript apps, but it's much better if we
can send them content instead of letting them figure it out.
The solution to both of those problems is server rendering, also called static pre-rendering.
Next.js is one React framework to do all of this in a very simple way, but it's not limited to this.
It's advertised by its creators as a zero-configuration, single-command toolchain for React
apps.
It provides a common structure that allows you to easily build a frontend React application,
and transparently handle server-side rendering for you.
202
Next.js
Main features
Here is a non-exhaustive list of the main Next.js features:
Hot Code Reloading: Next.js reloads the page when it detects any change saved to disk.
Automatic Routing: any URL is mapped to the filesystem, to files put in the pages
folder, and you don't need any configuration (you have customization options of course).
Single File Components: using styled-jsx, completely integrated as built by the same
team, it's trivial to add styles scoped to the component.
Server Rendering: you can (optionally) render React components on the server side,
before sending the HTML to the client.
Ecosystem Compatibility: Next.js plays well with the rest of the JavaScript, Node and
React ecosystem.
Automatic Code Splitting: pages are rendered with just the libraries and JavaScript that
they need, no more.
Prefetching: the Link component, used to link together different pages, supports a
prefetch prop which automatically prefetches page resources (including code missing
Installation
Next.js supports all the major platforms: Linux, macOS, Windows.
or with Yarn:
Getting started
Create a package.json file with this content:
203
Next.js
{
"scripts": {
"dev": "next"
}
}
the script will raise an error complaining about not finding the pages folder. This is the only
thing that Next.js requires to run.
Create an empty pages folder, and run the command again, and Next.js will start up a server
on localhost:3000 .
If you go to that URL now, you'll be greeted by a friendly 404 page, with a nice clean design.
Next.js handles other error types as well, like 500 errors for example.
Create a page
In the pages folder create an index.js file with a simple React functional component:
204
Next.js
Next.js uses a declarative pages structure, which is based on the filesystem structure.
Simply put, pages are inside a pages folder, and the page URL is determined by the page file
name. The filesystem is the pages API.
Server-side rendering
Open the page source, View -> Developer -> View Source with Chrome.
As you can see, the HTML generated by the component is sent directly in the page source. It's
not rendered client-side, but instead it's rendered on the server.
The Next.js team wanted to create a developer experience for server rendered pages similar
to the one you get when creating a basic PHP project, where you simply drop PHP files and
you call them, and they show up as pages. Internally of course it's all very different, but the
apparent ease of use is clear.
If you point your browser to localhost:3000/contact this page will be rendered. As you can
see, also this page is server rendered.
Hot reloading
Note how you did not have to restart the npm process to load the second page. Next.js does
this for you under the hood.
Client rendering
205
Next.js
Server rendering is very convenient in your first page load, for all the reasons we saw above,
but when it comes to navigating inside the website, client-side rendering is key to speeding up
the page load and improving the user experience.
Next.js provides a Link component you can use to build links. Try linking the two pages
above.
Now go back to the browser and try this link. As you can see, the Contact page loads
immediately, without a page refresh.
This is client-side navigation working correctly, with complete support for the History API,
which means your users back button won't break.
If you now cmd-click the link, the same Contact page will open in a new tab, now server
rendered.
Dynamic pages
A good use case for Next.js is a blog, as it's something that all developers know how it works,
and it's a good fit for a simple example of how to handle dynamic pages.
A dynamic page is a page that has no fixed content, but instead display some data based on
some parameters.
Change index.js to
206
Next.js
This will create a series of posts and will fill the title query parameter with the post title:
Now clicking a single post will render the post title in a h1 tag:
You can use clean URLs without query parameters. The Next.js Link component helps us by
accepting an as attribute, which you can use to pass a slug:
207
Next.js
CSS-in-JS
Next.js by default provides support for styled-jsx, which is a CSS-in-JS solution provided by
the same development team, but you can use whatever library you prefer, like Styled
Components.
Example:
208
Next.js
Styles are scoped to the component, but you can also edit global styles adding global to the
style element:
The process requires you to declare the URLs that compose the site, but it's a straightforward
process.
Deploying
Creating a production-ready copy of the application, without source maps or other
development tooling that aren't needed in the final build, is easy.
At the beginning of this tutorial you created a package.json file with this content:
{
"scripts": {
"dev": "next"
}
}
which was the way to start up a development server using npm run dev .
209
Next.js
{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}
and prepare your app by running npm run build and npm run start .
Now
The company behind Next.js provides an awesome hosting service for Node.js applications,
called Now.
Of course they integrate both their products so you can deploy Next.js apps seamlessly, once
you have Now installed, by running the now command in the application folder.
Behind the scenes Now sets up a server for you, and you don't need to worry about anything,
just wait for your application URL to be ready.
Zones
You can set up multiple Next.js instances to listen to different URLs, yet the application to an
outside user will simply look like it's being powered by a single server:
https://github.com/zeit/next.js/#multi-zones
Plugins
Next.js has a list of plugins at https://github.com/zeit/next-plugins
210
Next.js
211
Gatsby
Gatsby
Gatsby is a platform for building apps and websites using React
It is one of the tools that allow you to build on a set of technologies and practices collectively
known as JAMstack.
Gatsby is one of the cool kids in the Frontend Development space right now. Why? I think the
reasons are:
the explosion of the JAMstack approach to building Web Apps and Web Sites
the rapid adoption of the Progressive Web Apps technology in the industry, which is one
of the key features of Gatsby
it's built in React and GraphQL, which are two very popular and rising technologies
it's really powerful
it's fast
the documentation is great
the network effect (people use it, create sites, make tutorials, people know more about it,
creating a cycle)
everything is JavaScript (no need to learn a new templating language)
it hides the complexity, in the beginning, but allows us access into every step to customize
All those are great points, and Gatsby is definitely worth a look.
212
Gatsby
The content you'll render in a site is generally written using Markdown, but you can use any
kind of data source, like an headless CMS or a web service like Contentful.
Gatsby builds the site, and it's compiled to static HTML which can be deployed on any Web
Server you want, like Netlify, AWS S3, GitHub Pages, regular hosting providers, PAAS and
more. All you need is a place that serves plain HTTP pages and your assets to the client.
I mentioned Progressive Web Apps in the list. Gatsby automatically generates your site as a
PWA, with a service worker that speeds up page loading and resource caching.
Installation
You can install Gatsby by simply running this in your terminal:
This command creates a brand new Gatsby site in the mysite folder, using the starter
available at https://github.com/gatsbyjs/gatsby-starter-hello-world.
213
Gatsby
A starter is a sample site that you can build upon. Another common starter is default ,
available at https://github.com/gatsbyjs/gatsby-starter-default.
Here you can find a list of all the starters you can use
cd mysite
gatsby develop
which will start up a new Web Server and serve the site on port 8000 on localhost.
214
Gatsby
215
Gatsby
.cache , an hidden folder that contains the Gatsby internals, nothing you should change
right now
public , which contains the resulting website once you build it
src contains the React components, in this case just the index component
static which will contain the static resources like CSS and images
216
Gatsby
Now, making a simple change to the default page is easy, just open src/pages/index.js and
change "Hello world!" to something else, and save. The browser should instantly hot reload
the component (which means the page does not actually refresh, but the content changes - a
trick made possible by the underlying technology).
To add a second page, just create another .js file in this folder, with the same content of
index.js (tweak the content) and save it.
217
Gatsby
Linking pages
You can link those pages by importing a Gatsby-provided React component called Link :
<Link to="/second/">Second</Link>
Adding CSS
You can import any CSS file using a JavaScript import:
import './index.css'
<p style={{
margin: '0 auto',
padding: '20px'
218
Gatsby
}}>Hello world</p>
Using plugins
Gatsby provides lots of things out of the box, but many other functionalities are provided by
plugins.
source plugins fetch data from a source. Create nodes that can be then filtered by
transformer plugins
transformer plugins transform the data provided by source plugins into something
Gatsby can use
functional plugins implement some kind of functionality, like adding sitemap support or
more
A Gatsby plugin is installed in 2 steps. First you install it using npm , then you add it to the
Gatsby configuration in gatsby-config.js .
In gatsby-config.js (create it if you don't have it, in the website root folder), add the plugin to
the plugins exported array:
module.exports = {
plugins: ['gatsby-plugin-catch-links']
}
219
Gatsby
gatsby build
At this point you can check that it all works as you expect by starting a local Web Server using
gatsby serve
which will render the site as close as possible to how you will see it in production.
Deployment
Once you build the site using gatsby build , all you need to do is to deploy the result
contained in the public folder.
Depending on the solution you choose, you'll need different steps here, but generally you'll
push to a Git repository and let the Git post-commit hooks do the job of deploying.
Here are some great guides for some popular hosting platforms.
220
Wrapping up
Wrapping up
I hope the book helped you get started with React, and maybe it gave you a head start in
exploring some of the most advanced aspects of React programming.
I will soon release a practical online course to apply those concepts. Stay tuned.
221