The React Handbook
The React Handbook
The React Handbook follows the 80/20 rule: learn in 20% of the time
the 80% of a topic.
I hope the contents of this book will help you achieve what you want:
learn the basics of React.
You can get this ebook in PDF, ePub and Mobi format at
reacthandbook.com
Book Index
Table of Contents
An introduction to React
How to use create-react-app
• Variables
• Arrow functions
• Template literals
• Classes
• Callbacks
• Promises
• Async/Await
• ES Modules
• Declarative
• Immutability
• Purity
• Composition
• JSX
• Components
• State
• Props
• State vs props
• PropTypes
• React Fragment
• Events
• Lifecycle Events
• Forms in React
• Render Props
• Hooks
• Code splitting
SECTION 5: STYLING
• CSS in React
• SASS in React
• Styled Components
SECTION 6: TOOLING
• Babel
• Webpack
SECTION 7: TESTING
• Jest
• React Router
• Redux
• Next.js
• Gatsby
Wrapping up
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 di erent framework,
so this, along with execution speed improvements that React promised,
made it something developers were eager to try.
Backed by Facebook
Being backed by Facebook is, of course, going to bene t a project if it
turns out to be successful.
React in itself has a very small API, and you basically need to
understand 4 concepts to get started:
• Components
• JSX
• State
• Props
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.development.js"
crossorigin
></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/react-
dom/16.7.0-alpha.2/umd/react-dom.production.min.js"
crossorigin
></script>
</body>
</html>
Here we loaded both React and React DOM. Why 2 libraries? Because
React is 100% independent from the browser and can be used outside it
(for example on Mobile devices with React Native). Hence the need for
React DOM, to add the wrappers for the browser.
After those tags you can load your JavaScript les 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 work ow.
You start by using npx , which is an easy way to download and execute
Node.js commands without installing them. npx comes with npm
(since version 5.2) and if you don't have npm installed already, do it
now from https://nodejs.org (npm is installed with Node).
If you are unsure which version of npm you have, run npm -v to check
if you need to update.
Tip: check out my OSX terminal tutorial if you’re unfamiliar with using
the terminal, applies to Linux as well — I’m sorry but I don’t have a
tutorial for Windows at the moment, but Google is your friend.
• npm run build : to build the React application les in the build
When you eject, you lose the ability of automatic updates but you gain
more exibility in the Babel and Webpack con guration.
When you eject the action is irreversible. You will get 2 new folders in
your application directory, config and scripts . Those contain the
con gurations - and now you can start editing them.
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".
Codepen
Another great solution is Codepen.
You can use this Codepen starter project which already comes pre-
con gured with React, with support for Hooks:
https://codepen.io/ aviocopes/pen/VqeaxB
Codepen “pens” are great for quick projects with one JavaScript le,
while “projects” are great for projects with multiple les, 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
and not
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.
Variables
A variable is a literal assigned to an identi er, so you can reference and
use it later in the program.
Variables in JavaScript do not have any type attached. Once you assign
a speci c literal type to a variable, you can later reassign the variable to
host any other type, without type errors or any issue.
This is why JavaScript is sometimes referred to as “untyped”.
A variable must be declared before you can use it. There are 3 ways to
do this, using var , let or const , and those 3 ways di er in how
you can interact with the variable later on.
Using var
Until ES2015, var was the only construct available for de ning
variables.
var a = 0
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:
var a = 1, b = 2
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 de ned, and all the contained inner blocks.
If let seems an obscure term, just read let color = 'red' as let the
color be red and it all makes much more sense
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 di erent value.
const a = 'test'
We can’t assign a di erent 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.
Arrow functions
Arrow functions were introduced in ES6 / ECMAScript 2015, and since
their introduction they changed forever how JavaScript code looks
(and works).
In my opinion this change was so welcoming that you now rarely see
the usage of the function keyword in modern codebases.
Visually, it’s a simple and welcome change, which allows you to write
functions with a shorter syntax, from:
to
If the function body contains just a single statement, you can omit the
brackets and write all on a single line:
const myFunction = () => doSomething()
If you have one (and just one) parameter, you could omit the
parentheses completely:
Implicit return
Arrow functions allow you to have an implicit return: values are
returned without having to use the return keyword.
myFunction() //'test'
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: () => {
return `${this.manufacturer} ${this.model}`
}
}
const a = [1, 2, 3]
const b = [...a, 4, 5, 6]
const c = [...a]
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)
ES2018 introduces rest properties, which are the same but for objects.
Rest properties:
first // 1
second // 2
others // { third: 3, fourth: 4, fifth: 5 }
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 :
const [first, second, , , fifth] = a
Template literals
Template Literals are a new ES2015 / ES6 feature that allows you to
work with strings in a novel way compared to ES5 and below.
The syntax at a rst 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:
• they allow you to create DSLs with template tags (DSL means
domain speci c language, and it’s for example used in React by
Styled Components, to de ne CSS for a component)
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:
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
const string = `
First
Second`.trim()
Interpolation
Template literals provide an easy way to interpolate variables and
expressions into strings.
Classes
In 2015 the ECMAScript 6 (ES6) standard introduced classes.
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 de nition
This is how a class looks.
class Person {
constructor(name) {
this.name = name
}
hello() {
return 'Hello, I am ' + this.name + '.'
}
}
A class has an identi er, which we can use to create new objects using
new ClassIdentifier() .
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 de ned 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 de ne private or protected
methods.
class Person {
constructor(name) {
this.name = name
}
set name(value) {
this.name = value
}
get name() {
return this.name
}
}
If you only have a getter, the property cannot be set, and any attempt at
doing so will be ignored:
class Person {
constructor(name) {
this.name = name
}
get name() {
return this.name
}
}
If you only have a setter, you can change the value but not access it
from the outside:
class Person {
constructor(name) {
this.name = name
}
set name(value) {
this.name = value
}
}
Callbacks
Computers are asynchronous by design.
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 nishes.
Lines of code are executed in series, one after another, for example:
const a = 1
const b = 2
const c = a * b
console.log(c)
doSomething()
But JavaScript was born inside the browser, its main job, in the
beginning, was to respond to user actions, like onClick , onMouseOver ,
onChange , onSubmit and so on. How could it do this with a
synchronous programming model?
You can’t know when a user is going to click a button, so what you do is,
you de ne 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
})
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)
However every callback adds a level of nesting, and when you have lots
of callbacks, the code starts to be complicated very quickly:
window.addEventListener('load', () => {
document.getElementById('button').addEventListener('click',
() => {
setTimeout(() => {
items.forEach(item => {
//your code here
})
}, 2000)
})
})
This is just a simple 4-levels code, but I’ve seen much more levels of
nesting and it’s not fun.
ALTERNATIVES TO CALLBACKS
Starting with ES6, JavaScript introduced several features that help us
with asynchronous code that do not involve using callbacks:
• Promises (ES6)
• Async/Await (ES8)
Promises
Promises are one way to deal with asynchronous code, without writing
too many callbacks in your code.
Although they’ve been around for years, they were standardized and
introduced in ES2015, and now they have been superseded in ES2017
by async functions.
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.
Creating a promise
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.
Consuming a promise
In the last section, we introduced how a promise is created.
Chaining promises
A promise can be returned to another promise, creating a chain of
promises.
Example:
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 le found in the domain root, and we create a chain of
promises.
So given those premises, this is what happens: the rst promise in the
chain is a function that we de ned, called status() , that checks the
response status and if it's not a success response (between 200 and
299), it rejects the promise.
This operation will cause the promise chain to skip all the chained
promises listed and will skip directly to the catch() statement at the
bottom, logging the Request failed text along with the error
message.
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.
// or
Cascading errors
If inside the catch() you raise an error, you can append a second
catch() to handle it, and so on.
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.
Example:
Async/Await
JavaScript evolved in a very short time from callbacks to promises
(ES2015), and since ES2017 asynchronous JavaScript is even simpler
with the async/await syntax.
How it works
An async function returns a promise, like in this example:
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 de ned 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
And this is a very simple example, the major bene ts will arise when
the code is much more complex.
For example here’s how you would get a JSON resource, and parse it,
using promises:
const getFirstUserData = () => {
return fetch('/users.json') // get users list
.then(response => response.json()) // parse JSON
.then(users => users[0]) // pick first user
.then(user => fetch(`/users/${user.name}`)) // get user
data
.then(userResponse => response.json()) // parse JSON
}
getFirstUserData()
getFirstUserData()
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.
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 rst standardized by ECMAScript and then
implemented by the browser.
Modules are very cool, because they let you encapsulate all sorts of
functionality, and expose this functionality to other JavaScript les, as
libraries.
uppercase.js
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
e ciently load JavaScript with defer and async
toUpperCase('test') //'TEST'
You can also use an absolute path for the module import, to reference
modules de ned on another domain:
This is not:
This creates one default export. In a le 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: * )
What about browsers that do not support modules?
Use a combination of type="module" and nomodule :
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.
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.
The technology is always the same, but the philosophy and some key
components of how the application works are di erent.
• Gmail
• Google Maps
• Google Drive
In addition to making the experience faster to the user, the server will
consume less resources because you can focus on providing an e cient
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.
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 problem can now be solved using the History API o ered by
browsers, but most of the time you’ll use a library that internally uses
that API, like React Router.
Declarative
What does it mean when you read that React is declarative? You’ll run
across articles describing React as a declarative approach to building
UIs.
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 speci c way, and we never
have to interact with the DOM to reference it later.
Immutability
One concept you will likely meet when programming in React is
immutability (and its opposite, mutability).
It’s a controversial topic, but whatever you might think about the
concept of immutability, React and most of its ecosystem kind of forces
this, so you need to at least have a grasp of why it’s so important and
the implications of it.
Instead of changing an array, to add a new item you create a new array
by concatenating the old array, plus the new item.
In Redux, you never mutate the state directly, but only through
reducers, which are functions.
• The library can optimize the code because for example JavaScript
is faster when swapping an old object reference for an entirely new
object, rather than mutating an existing object. This gives you
performance.
Purity
In JavaScript, when a function does not mutate objects but just returns
a new object, it’s called a pure function.
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.
Composition
In programming, composition allows you to build more complex
functionality by combining small and focused functions.
For example, think about using map() to create a new array from an
initial set, and then ltering the result using filter() :
Using children
The props.children property allows you to inject components inside
other components.
<Sidebar>
<Link title="First link" />
<Link title="Second link" />
</Sidebar>
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, lter 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.
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.
• it’s less error prone, as you have more control over your data
This is the reason that the state is often moved up in the Component
tree, so that it can be shared between components that need to access
it.
SECTION 3: IN-DEPTH REACT
JSX
JSX is a technology that was introduced by React.
At rst, 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 de ne a h1 tag containing a string:
It looks like a strange mix of JavaScript and HTML, but in reality it’s all
JavaScript.
You just need to pay attention when an attribute has a dash ( - ) which
is converted to camelCase syntax instead, and these 2 special cases:
• class becomes className
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.
Transpiling JSX
A browser cannot execute JavaScript les containing JSX code. They
must be rst transformed to regular JS.
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.
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 de ned elsewhere:
As you can see we nested JavaScript inside JSX de ned 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 di erences
between how you would de ne some things in HTML, and how you
de ne them in JSX.
<p class="description">
CSS in React
JSX provides a cool way to de ne CSS.
If you have a little experience with HTML inline styles, at rst glance
you’ll nd 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 x” go-to solution).
JSX style is not the same thing: rst of all, instead of accepting a string
containing CSS properties, the JSX style attribute only accepts an
object. This means you de ne properties in an object:
var divStyle = {
color: 'white'
}
or
The CSS values you write in JSX are slightly di erent from plain CSS:
2. style animations
In short, they cover the basics, but it’s not the nal 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 eld was created.
This helps solve some weird behavior of regular DOM interaction when
inspecting input.value and input.getAttribute('value') returning
one the current value and one the original default value.
<textarea>Some text</textarea>
but instead
<select>
<option value="x" selected>
...
</option>
</select>
use
<select defaultValue="x">
<option value="x">...</option>
</select>
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 x this you can either move the entities outside the expression:
<p>© 2017</p>
<p>{'\u00A9 2017'}</p>
If you have white space between elements in the same line, it’s all
trimmed to 1 white space.
becomes
<p>
Something
becomes
this
</p>
becomes
<p>Somethingbecomesthis</p>
To x 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>
<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>
you can pass
<div>
<BlogPost {...data} />
</div>
const items = []
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:
const elements = ['one', 'two', 'three'];
return (
<ul>
{elements.map((value, index) => {
return <li key={index}>{value}</li>
})}
</ul>
)
Components
A component is one isolated piece of interface. For example in a typical
blog homepage you might nd 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(<h1>Hello World!</h1>,
document.getElementById('app'))
ReactDOM.render(
React.DOM.h1(null, 'Hello World!'),
document.getElementById('app')
)
Custom components
There are 2 ways to de ne a component in React.
A function component:
A class component:
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>
)
}
})
State
Setting the default state of a component
In the Component constructor, initialize this.state . For example the
BlogPostExcerpt component might have a clicked state:
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>
)
}
}
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.
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:
render() {
return (
<div>
<Display currency={this.state.currency} />
<CurrencySwitcher currency={this.state.currency} />
</div>
)
}
}
render() {
return (
<div>
<Display currency={this.state.currency} />
<CurrencySwitcher
currency={this.state.currency}
handleChangeCurrency={this.handleChangeCurrency}
/>
</div>
)
}
}
Props
Props is how Components get their properties. Starting from the top
component, every child component gets its props from the parent. In a
function component, props is all it gets passed, and they are available
by adding props as the function argument:
BlogPostExcerpt.propTypes = {
title: PropTypes.string,
description: PropTypes.string
}
BlogPostExcerpt.defaultProps = {
title: '',
description: ''
}
Some tooling like ESLint have the ability to enforce de ning the
defaultProps for a Component with some propTypes not explicitly
required.
Children
A special prop is children . That contains the value of anything that is
passed in the body of the component, for example:
They don’t manage any kind of state, except for state related the the
presentation
componentDidMount() {
axios.get('/users').then(users =>
this.setState({ users: users }))
)
}
render() {
return <Users users={this.state.users} />
}
}
State vs props
In a React component, props are variables passed to it by its parent
component. State on the other hand is still variables, but directly
initialized and managed by the component.
<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:
In this case there’s nothing useful going on, but imagine doing
something di erent 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.
PropTypes
Since JavaScript is a dynamically typed language, we don’t really have a
way to enforce the type of a variable at compile time, and if we pass
invalid types, they will fail at runtime or give weird results if the types
are compatible but not what we expect.
Flow and TypeScript help a lot, but React has a way to directly help
with props types, and even before running the code, our tools (editors,
linters) can detect when we are passing the wrong values:
BlogPostExcerpt.propTypes = {
title: PropTypes.string,
description: PropTypes.string
}
• PropTypes.bool
• PropTypes.func
• PropTypes.number
• PropTypes.object
• PropTypes.string
• PropTypes.symbol
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,
React Fragment
Notice how I wrap return values in a div . This is because a component
can only return one single element, and if you want more than one, you
need to wrap it with another container tag.
which also has a very nice shorthand syntax <></> that is supported
only in recent releases (and Babel 7+):
Events
React provides an easy way to manage events. Prepare to say goodbye
to addEventListener .
In the previous article about the State you saw this example:
If you’ve been using JavaScript for a while, this is just like plain old
JavaScript event handlers, except that this time you’re de ning
everything in JavaScript, not in your HTML, and you’re passing a
function, not a string.
The actual event names are a little bit di erent 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 de ned as methods on the
Component class:
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
• onBlur
Form
• onChange
• onInput
• onSubmit
Mouse
• onClick
• onContextMenu
• onDoubleClick
• onDrag
• onDragEnd
• onDragEnter
• onDragExit
• onDragLeave
• onDragOver
• onDragStart
• onDrop
• onMouseDown
• onMouseEnter
• onMouseLeave
• onMouseMove
• onMouseOut
• onMouseOver
• onMouseUp
Selection
• onSelect
Touch
• onTouchCancel
• onTouchEnd
• onTouchMove
• onTouchStart
UI
• onScroll
Mouse Wheel
• onWheel
Media
• onAbort
• onCanPlay
• onCanPlayThrough
• onDurationChange
• onEmptied
• onEncrypted
• onEnded
• onError
• onLoadedData
• onLoadedMetadata
• onLoadStart
• onPause
• onPlay
• onPlaying
• onProgress
• onRateChange
• onSeeked
• onSeeking
• onStalled
• onSuspend
• onTimeUpdate
• onVolumeChange
• onWaiting
Image
• onLoad
• onError
Animation
• onAnimationStart
• onAnimationEnd
• onAnimationIteration
Transition
• onTransitionEnd
Lifecycle Events
React class components can have hooks for several lifecycle events.
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 rst 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 e ects and should return
the same output when called multiple times with the same input.
Returns an object with the updated elements of the state (or null if the
state does not change)
render()
From the render() method you return the JSX that builds the
component interface.
It’s a pure method, so it should not cause side e ects 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.
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.
Forms in React
Forms are one of the few HTML elements that are interactive by
default.
• Contact forms
• and more!
Using React we can make our forms much more interactive and less
static.
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 elds are inherently uncontrolled because of their
behavior, like the <input type="file"> eld.
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
handleChange(event) {
this.setState({ value: event.target.value })
}
render() {
return (
<form>
<input
type="text"
value={this.state.username}
onChange={this.handleChange}
/>
</form>
)
}
}
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>
)
}
}
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) elds using its value attribute.
In this case you need to get a reference to the eld by assigning the
ref attribute to a property de ned in the constructor with
React.createRef() , and use that to get the value of it in the submit
handler:
class FileInput extends React.Component {
constructor(props) {
super(props)
this.curriculum = React.createRef()
this.handleSubmit = this.handleSubmit.bind(this)
}
handleSubmit(event) {
alert(this.curriculum.current.files[0].name)
event.preventDefault()
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="file" ref={this.curriculum} />
<input type="submit" value="Submit" />
</form>
)
}
}
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:
function SomeComponent() {
let button
return <button ref={el => (button = el)} />
}
• 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.
• 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
To understand how SSR works, let’s start from the basics to implement
a proof of concept.
Feel free to skip this paragraph if you just want to look into the libraries
that provide SSR and not bother with the ground work
If you are new to Express, or need some catch-up, check out my free
Express Handbook here: https:// aviocopes.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.
You have a set of folders in your app directory. Create a new folder
called server , then go into it and create a le named server.js .
You get the contents of the ./build/index.html le, 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.
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}`)
})
require('ignore-styles')
require('@babel/register')({
ignore: [/(node_modules)/],
presets: ['@babel/preset-env', '@babel/preset-react']
})
require('./server')
node server/index.js
It’s still very much debatable if it’s worth the trouble, complication and
overhead to get the bene ts, rather than using a di erent 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.
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.
render() {
return (
<Provider value={{ state: this.state }}>
{this.props.children}</Provider>
)
}
}
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 les, you create the content in one le, 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'
//... use Context.Consumer
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.
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:
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.
Render Props
A common pattern used to share state between components is to use
the children prop.
render() {
return <div>{this.props.children}</div>
}
}
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>
}
}
Instead of using the children prop, which has a very speci c 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>
)
}
}
Hooks
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.
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
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
events, and those will serve many use cases, from variables
initialization to API calls to cleanup.
The function runs when the component is rst rendered, and on every
subsequent re-render/update. React rst updates the DOM, then calls
any function passed to useEffect() . All without blocking the UI
rendering even on blocking code, unlike the old componentDidMount
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')
)
useEffect(() => {
console.log(`Hi ${name} you clicked ${count} times`)
return () => {
console.log(`Unmounted`)
}
})
useEffect(
() => {
console.log(`Hi ${name} you clicked ${count} times`)
},
[name, count]
)
Similarly you can tell React to only execute the side e ect 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
Using custom hooks you have one more way to share state and logic
between components, adding a signi cant 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.
Examples:
const useGetData() {
//...
return data
}
or
const useGetUser(username) {
//...const user = fetch(...)
//...const userData = ...
return [user, userData]
}
In your own components, you can use the hook like this:
Code splitting
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 rst
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:
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>
...
Let’s use Codepen for this. We start by forking the React template pen.
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:
const Button = ({ increment, onClickFunction }) => {
const handleClick = () => {
onClickFunction(increment)
}
return <button onClick={handleClick}>+{increment}</button>
}
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>
)
}
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>
)
}
This code creates a reusable Card component. When you enter a name
in the input eld 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 .
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
The parent component is App, which stores the cards array in its own
state, managed using the useState() Hook:
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:
axios.get(`https://api.github.com/users/${username}`).then(r
esp => {
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.
return (
<div>
<Form onSubmit={addNewCard} />
<CardList cards={cards} />
</div>
)
}
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>
)
}
SECTION 5: STYLING
CSS in React
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 de ned in a slightly di erent way now. First, notice the double
curly brackets: it’s because style accepts an object. We pass in a
JavaScript object, which is de ned in curly braces. We could also do
this:
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 bene t 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 le can’t provide.
Add your CSS here, then import it inside the component le you want
to style:
That’s it! In the resulting markup, React will generate a speci c, unique
class for each rendered component, and assign the CSS to that class, so
that the CSS is not a ecting other markup.
SASS in React
When you build a React application using create-react-app , you have
many options at your disposal when it comes to styling.
You can use it without any con guration at all, starting with create-
react-app 2.
All you need is a .sass or .scss le, and you just import it in a
component:
import './styles.scss'
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.
• React Style
• jsxstyle
• Radium
and more.
Installation
Simply install styled-components using npm or yarn:
Now this component can be rendered in our container using the normal
React syntax:
render(<Button />)
The syntax used, with the backtick, might be weird at rst, but it’s
called Tagged Templates, it’s plain JavaScript and it’s a way to pass an
argument to the function.
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>
)
render(
<div>
<Button>A black button, like all buttons</Button>
<WhiteButton>A white button</WhiteButton>
</div>
)
SECTION 6: TOOLING
Babel
Babel is an awesome tool, and it’s been around for quite some time, but
nowadays almost every JavaScript developer relies on it. 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?
You can con gure 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 work ow 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)
Installing Babel
Babel is easily installed using npm, locally in a project:
Since npm now comes with npx , locally installed CLI packages can run
by typing the command in the project folder:
{
"plugins": ["transform-es2015-arrow-functions"]
}
TIP: If you have never seen a dot le (a le starting with a dot) it might
be odd at rst because that le might not appear in your le manager,
as it’s a hidden le.
var bob = {
_name: "Bob",
_friends: ["Sally", "Tom"],
printFriends() {
this._friends.forEach(f =>
console.log(this._name + " knows " + f));
}
};
console.log(bob.printFriends());
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 con gured to
transpile speci c JavaScript features.
You can add much more plugins, but you can’t add to the con guration
features one by one, it’s not practical.
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.
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']
}
}
]
}
Webpack
Webpack is a tool that lets you compile JavaScript modules, also known
as module bundler. Given a large number of les, it generates a single
le (or a few les) that run your app.
• can run Babel transpilation to ES5, allowing you to use the latest
JavaScript features without worrying about browser support.
• can split the output les into multiple les, to avoid having a huge
js le to load in the rst page hit.
• Grunt
• Broccoli
• Gulp
There are lots of similarities in what those and Webpack can do, but the
main di erence 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 le with script tags) and webpack analyzes the les
and bundles all you need to run the app in a single JavaScript output
le (or in more les 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:
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"
}
}
yarn build
You can customize every little bit of webpack of course, when you need.
The webpack con guration is stored in the webpack.config.js le, 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'
}
/*...*/
}
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 le, 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
}
}
]
}
]
}
/*...*/
}
The order matters, and it’s reversed (the last is executed rst).
What kind of loaders are there? Many! You can nd the full list here.
module.exports = {
/*...*/
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
/*...*/
}
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()
]
/*...*/
}
module.exports = {
entry: './index.js',
mode: 'development',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js'
}
}
Development mode:
Running webpack
Webpack can be run from the command line manually if installed
globally, but generally you write a script inside the package.json le,
which is then run using npm or yarn .
or
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
yarn run watch
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 a ected 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: [
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
/*...*/
}
file-loader can handle other asset types as well, like fonts, CSV les,
xml, and more.
This example loads any PNG le smaller than 8KB as a data URL.
module.exports = {
/*...*/
module: {
rules: [
{
test: /\.png$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
}
/*...*/
}
module.exports = {
/*...*/
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
]
}
/*...*/
}
Generate Source Maps
Since webpack bundles the code, Source Maps are mandatory to get a
reference to the original le that raised an error, for example.
You tell webpack to generate source maps using the devtool property
of the con guration:
module.exports = {
/*...*/
devtool: 'inline-source-map',
/*...*/
}
devtool has many possible values, the most used probably are:
SECTION 7: TESTING
Jest
Jest is a library for testing JavaScript code.
• it’s fast
• Mocha requires more con guration, while Jest works usually out
of the box, thanks to being opinionated
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:
{
"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.
{
"scripts": {
"test": "jest"
}
}
Now, you don’t have any tests here, so nothing is going to be executed:
Let’s create the rst test. Open a math.js le and type a couple
functions that we’ll later test:
Now create a math.test.js le, in the same folder, and there we’ll use
Jest to test the functions de ned in math.js :
Running yarn test results in Jest being run on all the test les it nds,
and returning us the end result:
Run Jest with VS Code
Visual Studio Code is a great editor for JavaScript development. The
Jest extension o ers a top notch integration for our tests.
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 les that have a test (or a test le):
Matchers
In the previous article I used toBe() as the only matcher:
All those matchers can be negated using .not. inside the statement,
for example:
test('Adding 1 + 1 does not equal 3', () => {
expect(sum(1, 1)).not.toBe(3)
})
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
})
beforeEach(() => {
//do something
})
Teardown
Just as you can do with setup, you can also perform something after
each test runs:
afterEach(() => {
//do something
})
and after all tests end:
afterAll(() => {
//do something
})
Callbacks
You can’t have a test in a callback, because Jest won’t execute it — the
execution of the test le ends before the callback is called. To x 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')
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')
})
})
//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('').catch(e => {
expect(e).toMatch('Empty string')
})
})
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')
test(`uppercase 'test' to equal 'TEST'`, async () => {
const str = await uppercase('test')
expect(str).toBe('TEST')
})
Mocking
In testing, mocking allows you to test functionality that depends on:
• Database
• Network requests
• access to Files
so that:
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 e ects (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:
Example:
expect(mathjs.log).toHaveBeenCalled()
expect(mathjs.log).toHaveBeenCalledWith(10000, 10)
})
Mock an entire package
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 le for each of your packages.
module.exports = {
log: jest.fn(() => 'test')
}
This will mock the log() function of the package. Add as many
functions as you want to mock:
Snapshot testing
Snapshot testing is a pretty cool feature o ered 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.
the rst time you run this test, Jest saves the snapshot to the
__snapshots__ folder. Here’s what App.test.js.snap contains:
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:
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.
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 --
If you are familiar with testing software, it’s just like unit testing you do
for classes: you test each component functionality.
It’s just 2 components: App and Button. Create the App.js le:
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>
)
}
library , two helpers. The rst lets us render JSX. The second lets us
emit events on a component.
Create a Button.test.js and put it in the same folder as Button.js .
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
let count
Then we get the content of the rst 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
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:
expect(buttons[0].textContent).toBe('+1')
expect(buttons[1].textContent).toBe('+10')
expect(buttons[2].textContent).toBe('+100')
expect(buttons[3].textContent).toBe('+1000')
React Router
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.
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.
React Router o ers a way to write your code so that it will show
certain components of your app only if the route matches what you
de ne.
Installation
With npm:
With Yarn:
yarn add react-router-dom
Types of routes
React Router provides two di erent 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 */
Components
The 3 components you will interact the most when working with React
Router are:
• Link
• Route
BrowserRouter
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')
)
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
di erent 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:
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 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.
Match multiple paths
You can have a route respond to multiple paths simply using a regex,
because path can be a regular expressions string:
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>
)}
/>
//...
//...
const posts = [
{ id: 1, title: 'First', content: 'Hello world!' },
{ id: 2, title: 'Second', content: 'Hello again!' }
]
//...
Redux
Redux is a state manager that’s usually used along with React, but it’s
not tied to that library — it can be used with other technologies as well,
but we’ll stick to React for the sake of the explanation..
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).
Actions
An Action is a JavaScript object that describes a change in a
minimal way (with just the information needed):
{
type: 'CLICKED_SIDEBAR'
}
Action creators
Actions Creators are functions that create actions.
function addItem(t) {
return {
type: ADD_ITEM,
title: t
}
}
dispatch(addItem('Milk'))
Reducers
When an action is red, something must happen, the state of the
application must change.
A reducer is a pure function that calculates the next State Tree based
on the previous State Tree, and the action dispatched.
• never mutate the state, but instead create a new one with
Object.assign({}, ...)
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 simpli ed with this simple model:
The state
{
list: [
{ title: "First item" },
{ title: "Second item" },
],
title: 'Groceries list'
}
A list of actions
store.getState()
store.dispatch(addItem('Something'))
unsubscribe()
Data Flow
Data ow 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.
Next.js
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.
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-
con guration, single-command toolchain for React apps.
Installation
Next.js supports all the major platforms: Linux, macOS, Windows.
or with Yarn:
{
"scripts": {
"dev": "next"
}
}
the script will raise an error complaining about not nding the pages
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 le with a simple React
functional component:
export default () => (
<div>
<p>Hello World!</p>
</div>
)
Simply put, pages are inside a pages folder, and the page URL is
determined by the page le name. The lesystem 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.
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
Server rendering is very convenient in your rst 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.
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 t for a simple example
of how to handle dynamic pages.
A dynamic page is a page that has no xed content, but instead display
some data based on some parameters.
Change index.js to
This will create a series of posts and will ll the title query parameter
with the post title:
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:
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:
export default () => (
<div>
<p>
<a href="mailto:my@email.com">Contact us!</a>
</p>
<style jsx>{`
p {
font-family: 'Courier New';
}
a {
text-decoration: none;
color: black;
}
a:hover {
opacity: 0.8;
}
`}</style>
</div>
)
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 nal build,
is easy.
{
"scripts": {
"dev": "next"
}
}
which was the way to start up a development server using npm run
dev .
{
"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
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 di erent 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
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:
• it’s built in React and GraphQL, which are two very popular and
rising technologies
• it’s fast
• the network e ect (people use it, create sites, make tutorials,
people know more about it, creating a cycle)
All those are great points, and Gatsby is de nitely worth a look.
How does it work?
With Gatsby, your applications are built using React components.
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.
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.
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 nd 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.
And here is our Hello World starter in action:
• src contains the React components, in this case just the index
component
• static which will contain the static resources like CSS and
images
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 le in this folder, with the
same content of index.js (tweak the content) and save it.
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 le using a JavaScript import:
import './index.css'
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 ltered by transformer plugins
module.exports = {
plugins: ['gatsby-plugin-catch-links']
}
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 di erent 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 where you can deploy Gatsby.
. . .
Wrapping up
I hope this book has 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. That’s my hope, at least.
You can get this ebook in PDF, ePub and Mobi format
at reacthandbook.com