Sie sind auf Seite 1von 234

Table

of Contents

BASICS
Introduction 1.1
Building blocks 1.2
JSX 1.3
Set up 1.4
Component introduction 1.5
Props 1.6
State 1.7
Methods 1.8
Thinking in Components 1.9
Conditional rendering 1.10
Life cycle 1.11
Dealing with input elements 1.12
Forms 1.13
Forms II - validation 1.14
Formik - part II 1.15
AJAX /HTTP 1.16

STYLING
styled-components 2.1
inline styling 2.2
sass/less 2.3

IMAGES
Adding images 3.1

ROUTING
1
Core concepts 4.1
Dealing with router and query params 4.2
Programmatic navigation 4.3
Dealing with lazy loading/ code splitting 4.4

ADVANCED
DataContext API 5.1
Decorators 5.2

PATTERNS
Render props 6.1
Hooks 6.2

TESTING
Jest 7.1
Nock 7.2
Enzyme 7.3
react-testing-library 7.4
cypress 7.5

REDUX
Redux - overview 8.1
Actions 8.2
Reducers 8.3
Store 8.4
Add Redux to React 8.5
Handling side effects with Sagas 8.6
Redux Form 8.7

2
MOBX
Observables 9.1
Computed variables 9.2
Reactions 9.3

LIBRARIES
storybook 10.1
Joi - awesome code validation 10.2

3
Introduction

React
React is a very popular choice when building a SPA, Single Page Application.

A Single Page Application differs from a normal web application in that you remain on the
same URL and thereby the same page, hence the name. To create many pages in a Single
Page Application we instead use the hash, # and listen to changes on it, for example
http://myapp.com#/products and http://myapp.com#/users is considered different pages in

a Single Page Application. More on routing in the Routing section.

React was created by Facebook.

The point of this book is to try to cover what I've learnt and hopefully make other people
better in the process. Everyone benefits from us being better at using something.

If you are new to React spend some time in the basic section before moving on. It's
important to know your basics ( I've learned this lesson the hard way :) )

The official documentation can be found at, https://reactjs.org/

Questions or comments, you can reach me on twitter:


@chris_noring

Credits
Than you to the React team at Facebook for all your efforts in creating React

Thank you John Papa for your PRs and suggestions and making this community book
better

This will always be a free resource

Happy reading
Chris

4
Building blocks

Building blocks
Components
JSX
React
ReactDOM

5
JSX

JSX
JSX is pretty much you writing XML in JavaScript. It's a preprocessor step. You don't have to
have it but it makes life a whole lot easier.

Simple example
This is a simple example on one line of code:

const Elem = <h1>Some title</h1>;

// and you can use it in React like so:


<div>
<Elem />
</div>

The above looks like XML in JavaScript. When it is being processed it is turned into the
following ES5 code:

React.createElement('Elem', null, 'Some title');

Ok so Elem becomes the element name, the second argument that above is null are our
element attributes, which we don't have any. The third and last argument is the elements
value. Let's look at an example below where we give it a property:

const Elem = <h1>Some title</h1>;

// usage:
<div>
<Elem title="a title">
</div>

The above would become the following code:

React.createElement('Elem', { title: 'a title' }, 'Some title');

Above we can see that our attribute title is now part of the second argument.

6
JSX

Multiline
Most o the time you will define JSX over several different rows and starting out new it might
stump you why it doesn't work. You simply need to wrap it in a parenthesis, like so:

const Elem =
(
<div>
<h1>Some title</h1>
<div>Some content</div>
</div>
)

One parent
JSX needs to have one parent. The following would be incorrect:

// would be incorrect, no parent element


const Elem =
(
<h1>Some title</h1>
<div>Some content</div>
)

We can fix this by either wrapping the in div element like so:

const Elem =
(
<div>
<h1>Some title</h1>
<div>Some content</div>
</div>
)

or we can wrap it in a React.Fragment, like so:

const Elem = (
<React.Fragment>
<h1>Some title</h1>
<div>Some content</div>
</React.Fragment>
)

7
JSX

React.Fragment would be the parent element needed instead of us using a div element just
to make JSX happy.

Summary
This is pretty much all we need to know on JSX to be able to work with it:

It's like XML that gets translated to React.createElement() calls


Multiline needs parenthesis to work
We need to have a parent element, React.Fragment is good option for that

8
Set up

Set up

unpkg/ script tags


This version is simplest to start with if you are beginner. This enables you to dive straight
into React and learn its features.

// app.js

class Application extends React.Component {


render() {
return (
<div>
App
</div>
);
}
}

ReactDOM.render(<Application />, document.getElementById('app'));

// index.html

<html>
<body>
<!-- This is where our app will live -->
<div id="app"></div>

<!-- These are script tags we need for React, JSX and ES2015 features -->
<script src="https://fb.me/react-15.0.0.js"></script>
<script src="https://fb.me/react-dom-15.0.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.
js"></script>
<script type="text/babel" src="app.js"></script>
</body>

</html>

You can easily serve this up by installing for example http-server

npm install http-server -g

and type:

9
Set up

http-server -p 5000

// should say 'App' in your browser at localhost:5000

The drawbacks to the above approach is that everything is compiled at runtime which is
horribly slow but its great for learning React, but please don't put it like this in production.

create-react-app
Create react is a scaffolder developed by Dan Abramov. With it you are able to scaffold a
React application with easy and is up and running in no time. The simplest way to get
started is downloading it, like so:

npm install create-react-app -g

Scaffolding an app is almost as simple as downloading it:

create-react-app <My app name>

create-react-app is a very active project and can truly help you in the beginning of you
learning React and even later. Question is really how much you want to be able to configure
your project. When you become skilled enough you may come to a point when you don't
need create-react-app, but until that point, it is your friend. You can read more on it in the
official documentation, https://github.com/facebook/create-react-app

do it yourself

10
Component introduction

Your first component


There are many ways to create a component but let's have a look at how you can create a
component. We use JSX to define it and assign it to a variable. Thereafter we are free to use
it in our markup. To create our component we need the following:

We need to inherit from React.Component


We need to implement a render() method that renders out in JSX what the component
should look like

Let's begin by creating a Jedi component:

class Jedi extends React.Component {


render() {
return (
<div>I am a Jedi Component</div>
);
}
}

// usage in markup

<div>
<Jedi />
</div>

Ok, great I know how to create a Component but how do I actually create a React app?
That's a fair comment. In the previous chapter Set up we show three different ways to help
you get started, unpkg, create-react-app and setting up your own project with Webpack. For
now let's stick to the simpler version with unpkg. For this we will need the following files:

index.html
app.js

11
Component introduction

// index.html

<html>
<body>
<!-- This is where our app will live -->
<div id="app"></div>

<!-- These are script tags we need for React, JSX and ES2015 features -->
<script src="https://fb.me/react-15.0.0.js"></script>
<script src="https://fb.me/react-dom-15.0.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.
js"></script>
<script type="text/babel" src="app.js"></script>
</body>

</html>

and app.js looks like the following:

class Jedi extends React.Component {


render() {
return (
<div>I am a Jedi Component</div>
);
}
}

class Application extends React.Component {


render() {
return (
<div>
<Jedi />
</div>
);
}
}

ReactDOM.render(<Application />, document.getElementById('app'));

12
Props

Introducing props
Adding props to your component means we add attributes to our component element. We
can read what these attributes are and make them part of the markup, like so:

const jediData = {
name: 'Yoda'
};

class Jedi extends React.Component {


render() {
return (
<div>{this.props.jedi.name}</div>
);
}
}

// example usage would be

<Jedi jedi={jediData} />

In the above code we assign jediData to the attribute jedi . An attribute on component is
known as a prop. To access it we simply need to type this.props.jedi . In the render()
method above we type this.props.jedi.name and thereby we access the object we
assigned to it and drill down to the name attribute.

Assigning a list
We usually deal with either rendering an object or a list or primitive. To render a list is almost
as simple as rendering an object. A list of Jedis is only about rendering a list Jedi
components, like so:

13
Props

const jedis = [{
name: 'Yoda'
},
{
name: 'Palpatine'
}]

class Jedis extends React.Component {


render() {
return (
<div>{this.props.jedis.map( jedi => <Jedi jedi={jedi} />)}</div>
);
}
}
}

class Jedi extends React.Component {


render() {
return (
<div>Name: {this.props.jedi.name}</div>
);
}
}

class App extends Component {


render() {
return (
<div>
<Jedis jedis={jedis} />
</div>
);
}
}

Above we use a simple map() function to output a list of Jedi elements. For each item in
the list we bind that to our jedi property on our Jedi component.

PropTypes
As our components becomes more and more complicated we want to ensure we use them
correctly. For example if a component has a certain property set it should render it. We might
even go so far as to convey that if a property is not set we should throw an error. The library
prop-types helps us to define what properties are a must and helps us define what type they
are. Let's download it and demonstrate those features:

14
Props

npm install prop-types


yarn add prop-types // or this one, depending on if you are using NPM or Yarn

Simply use it by:

importing it
define the properties your component should have and what type they are

Let's show the above in code:

import React, { Component } from 'react';


import PropType from 'prop-types';

class Jedi extends React.Component {


render() {
return (
<div>Name: {this.props.jedi.name}</div>
);
}
}

// 1. declaring the types it consists of


Jedi.propTypes = {
jedi : PropType.shape({
name: PropType.string.isRequired,
})
};

class App extends Component {


render() {
return (
<div>

<!-- 2. Giving it BAD input on purpose -->


<Jedi jedi={{ title: 'Vader' }} />

{jedis.map( jedi => <Jedi jedi={jedi} />)}


</div>
);
}
}

export default App;

What've done above is to import the prop-types, like so:

import PropType from 'prop-types';

15
Props

Thereafter we extended our component by assigning an object propTypes to it, like so:

Jedi.propTypes = {
jedi : PropType.shape({
name: PropType.string.isRequired,
})
};

Above we are saying that the property jedi is a complex shape that consist of a name
property.

Below in our markup we are provoking an error by creating a Jedi component and giving it
an object that does NOT fullfill the requirements we have on it:

<!-- 2. Giving it BAD input on purpose -->


<Jedi jedi={{ title: 'Vader' }} />

This produces the following error in our console:

index.js:2178 Warning: Failed prop type: The prop `jedi.name` is marked as required
in `Jedi`, but its value is `undefined`.

in Jedi (at App.js:33)

in App (at index.js:7)

The reason we get the above error message is that we provide an object with the property
title instead of name . If we were to change the above to the following, the error would

disappear:

<Jedi jedi={{ name: 'Vader' }} />

Best practice
It is considered best practice to use this lib. It is further considered a best practice to mark
up every single input with a specific type. Also it's considered a better practice to move in
the propTypes as member of the class, like so:

16
Props

class Jedi extends React.Component {


static propTypes = {
jedi : PropType.shape({
name: PropType.string.isRequired,
})
};

render() {
return (
<div>Name: {this.props.jedi.name}</div>
);
}
}

Summary
We introduce props. They are the way we are able to pass data into a component. We have
learned the following:

We simply declare them as attribute on our React element when we want to pass in
something <Elem attr={data}>
We can pass in object or a list, both works
We should use the library prop-types to ensure our component get the data they expect
so we can capture errors early

17
State

Dealing with state


State is how we can change the data inside of a component. In the former section we
covered props, Props . Props are great but they lack the ability to be changed in the
component they are added in. Let's look at the following example so you understand what I
mean:

import React, { Component } from 'react';


import PropTypes from 'prop-types';

class Element extends React.Component {


static propTypes = {
name: PropTypes.string
}

// THIS WON'T WORK


changeName() {
this.props.name = 'new name';
}

render() {
return (
<div>{this.props.name}</div>
<button onClick={() => this.changeName()} ></button>
)
}
}

// usage

let person = { name: 'chris' }

<Element name={person.name} />

In the above example we try to change the name property but React won't let us do that.
Instead we need to rely on state to do so.

Creating the state


There are two ways we can create the state:

declare it in the constructor


create it as inline field in the class

18
State

The first way looks like this:

class Element extends React.Component {


constructor() {
this.state = {
field : 'some value'
}
}
}

The second way looks like this:

class Element extends React.Component {


state = {
field : 'some value'
}
}

Accessing the state


Accessing the state is as simple as calling this.state.property . If you want to be more
elegant you can use destructuring like so:

render() {
// DESTRUCTURING
const { name } = this.props;

return (
<div>{name}</div>
<button onClick={() => this.changeName()} >Change name</button>
)
}

Changing the state


To change our state we need to call the setState() method and provide it the slice of
change we wan't to change here:

this.setState({
name: 'new name'
})

One important thing to know though. If the state object is way bigger than that, like so:

19
State

state = {
name : '',
products: []
}

Only the part you refer to in setState() will be affected.

Rewriting our example to use state


Let's rewrite the above to instead use state:

import React, { Component } from 'react';


import PropTypes from 'prop-types';

class Element extends React.Component {


static propTypes = {
name: PropTypes.string
}

constructor() {
this.state = {
name : this.props.name
}
}

changeName() {
this.setState({
name: 'new name'
})
}

render() {
return (
<div>{this.props.name}</div>
<button onClick={() => this.changeName()} >Change name</button>
)
}
}

// usage

let person = { name: 'chris' }

<Element name={person.name} />

Above we are now using the state functionality so we can change the value. We are
however creating a copy of the props value in the constructor :

20
State

constructor() {
this.state = {
name : this.props.name
}
}

Listen to the change


Changing the the state with setState() doesn't happen there and then, it takes a little time.
So doing something like this may lead to buggy code:

someMethod() {

this.setState({
name : 'some value'
});

if(this.state.name === 'some value') {


// do something
}
}

It's usually better to wait until you are in the render() method and then do your
comparison, like so:

21
State

import React, { Component } from 'react';

class Element extends React.Component {

constructor() {
this.state = {
show : false
}
}

toggleShow() {
this.setState({
show: !this.state.show
})
}

render() {
return (
<div>Element</div>

// better to access the state here, when it has its new value we act accordingly
{ this.state.show &&
<div>show this..</div>
}
<button onClick={() => this.toggleShow()} >Toggle</button>
)
}
}

// usage

<Element />

If you really want to know exactly when the change in the state happens, you can provide a
callback to setState() , like so:

someMethod() {

this.setState({
name : 'some value'
}, () => {
// state changed here
if(this.state.name === 'some value') {
// do something
}
});
}

22
State

23
Methods

Methods
When you build your component you are going to want to add methods to it. You are going
to attach methods to different events such as submit , click , change etc. One thing you
need to keep in mind is that React changes the name and the casing of the event like so:

click becomes onClick


change becomes onChange
submit becomes onSubmit

I think you get the idea.

Event examples
Let's have a look at how to set up a method to an event:

class Element extends React.Component {


clicked() {
console.log('clicked');
}

render() {
return (
<button onClick={this.clicked}></button>
)
}
}

Binding our method to our class


This looks all well and good but it has a problem. You don't see the problem right now cause
it does what it is supposed to i.e print clicked in the console. However try do the following
modification:

24
Methods

class Element extends React.Component {


state = {
str: 'test'
}

clicked() {
console.log('clicked ' + this.state.str);
}

render() {
return (
<button onClick={this.clicked}></button>
)
}
}

The above code WILL give out an error as it doesn't know what state is. This is because our
this points wrong. There are several ways to fix this. Let's look at the first one:

class Element extends React.Component {

constructor() {
super();
this.clicked = this.clicked.bind(this);
}

state = {
str: 'test'
}

clicked() {
console.log('clicked ' + this.state.str);
}

render() {
return (
<button onClick={this.clicked}></button>
)
}
}

We are above declaring a constructor and binding our method clicked() to the object
instance, like so:

constructor() {
super();
this.clicked = this.clicked.bind(this);
}

25
Methods

Two other versions of binding the method


At this point our code works again but it doesn't feel all too pretty. Is there a better way?
Actually there are two more ways we could solve this:

invoke our method as a lambda


declare our method as a field in the class

Invoke method as lambda


Let's look at the first mentioned variant:

In this version we use a lambda in the set up in the markup. The code looks like this:

class Element extends React.Component {

constructor() {
super();
this.clicked = this.clicked.bind(this);
}

state = {
str: 'test'
}

clicked() {
console.log('clicked ' + this.state.str);
}

render() {
return (
<button onClick={() => this.clicked()}></button>
)
}
}

Let's zoom in to the change:

<button onClick={() => this.clicked()}></button>

Declare method as a field


In this version we declare our method a little bit differently:

26
Methods

class Element extends React.Component {

constructor() {
super();
this.clicked = this.clicked.bind(this);
}

state = {
str: 'test'
}

clicked = () => {
console.log('clicked ' + this.state.str);
}

render() {
return (
<button onClick={this.clicked}></button>
)
}
}

Notice the difference between declaring the method in the old way, like this:

clicked() {
console.log('clicked ' + this.state.str);
}

Now we instead declare clicked as a field like so:

clicked = () => {
console.log('clicked ' + this.state.str);
}

This is the preferred way of declaring methods on a class.

The change event


So far we covered the click event and different ways to wire up an event to a class. The last
bit is important to get right or your code will be riddled with runtime errors. Now let's look at
more events namely the change event. This event is interesting to capture when we are
dealing with input fields. It is a way for us to keep track of what the input fields value is at a
given point before we for example press a button to submit the value. The code looks like
the following:

27
Methods

class Element extends React.Component {

state = {
str: 'test'
}

changed = (evt) => {


this.setState({
str: evt.target.value
});
}

clicked = () => {
console.log('current value of the input', this.state.str);
}

render() {
return (
<React.Fragment>
<input onChange={this.changed} placeholder="some value" >
<button onClick={this.clicked}>Save</button>
</React.Fragment>
)
}
}

Above we are hooking up the onChange event to the changed() method. In the changed()
method we are setting the state every time the onChange is invoked, which is on every key
up. Once we press our button we then read from our state.str and we can see that the
latest value of our input field is being printed out.

28
Thinking in Components

Thinking in components - building a todo


app
In this chapter we will learn:

How to break down an app into smaller components


Introduce the concepts: presentation/dumb component and container component

Thinking in components is about being able to break down an application in components.


Consider something as simple as a Todo application. It will most likely consist of a number of
components. Let's try and break that down.

A list of todos
We start off by a list of todos and we realise we need to be able to render said list. Before
we consider how we should render it out on the screen, let's think about the underlying data
structure.

A todo has a description. Next interesting thing to think about is how do we complete a todo.
The intention of having a list of things we need to carry out it as at some point in time we will
hopefully carry out those items on the list. Now we have to ask ourselves wether we want to
remove a finished item in our todo list or simply mark it as completed. We opt for the latter to
feel good about ourselves for completing it but also so what we can see what we have
carried out historically. This tells us something about our data structure. It should most likely
look something like this:

[{
title: 'clean',
done: false
}, {
title: 'do dishes',
done: false
}]

The above list seems like a reasonable design of the data structure and now we can turn to
trying to render it in React.

Rendering the list

29
Thinking in Components

Most likely we will try out with something like this:

{todos.map(todo => (
<div>
<input type="checkbox" checked={todo.done} /> {todo.title}
</div>
)}

At this point we are able to render our todo list but we are not able to change the value of the
todo. Let's build this out to a real React component class and add support for changing a
todo to done.

30
Thinking in Components

import React, { Component } from 'react';


import styled from 'styled-components';

import './App.css';

const todos = [{
title: 'clean',
done: false,
},
{
title: 'do the dishes',
done: true,
}];

const Todos = styled.div`


padding: 30px;
`;

const Todo = styled.div`


box-shadow: 0 0 5px gray;
padding: 30px;
margin-bottom: 10px;
`;

class App extends Component {


render() {
return (
<Todos>
<h2>Todos</h2>
{todos.map(todo => (
<Todo>
<input type="checkbox" checked={todo.done} /> {todo.title}
</Todo>
))}
</Todos>
);
}
}

export default App;

Above we have created a fully working component but we are yet to add support for
changing our todos . Let's do that next. We need to do the following:

listen to an onChange event when we check our checkbox


change the item in our todo list to reflect the change we just made

Listen to onChange is quite simple, we just need to add a method that listens to it like so:

31
Thinking in Components

<input type="checkbox" checked={todo.done} onChange={() => this.handleChange(todo)} />

After that we need to figure out a way to change a todo in our list. We could be altering the
todos list directly but the more React thing todo would be to create a todos state in the
component, like so:

state = {
todos
}

Let's now add the final code:

import React, { Component } from 'react';


import styled from 'styled-components';

import './App.css';

const todos = [{
title: 'clean',
done: false,
id: 1,
},
{
title: 'do the dishes',
done: true,
id: 2,
}];

const Todos = styled.div`


padding: 30px;
`;

const Todo = styled.div`


box-shadow: 0 0 5px gray;
padding: 30px;
margin-bottom: 10px;
`;

class App extends Component {


state = {
todos,
};

handleChecked = (todo) => {


const newTodos = this.state.todos.map(t => {
if (t.id === todo.id) {
return { ...t, done: !t.done };
}
return t;

32
Thinking in Components

});

this.setState({
todos: newTodos,
});
}

render() {
return (
<Todos>
<h2>Todos</h2>
{this.state.todos.map(todo => (
<Todo key={todo.id}>
<input type="checkbox" onChange={() => this.handleChecked(todo)} checked={
todo.done} />
{todo.title}
</Todo>
))}
</Todos>
);
}
}

export default App;

Let's zoom in on the handleChecked() method here to realise what we have done:

handleChecked = (todo) => {


const newTodos = this.state.todos.map(t => {
if (t.id === todo.id) {
return { ...t, done: !t.done };
}
return t;
});

this.setState({
todos: newTodos,
});
}

we go through the list, todo by todo until we find the selected todo then we change it state
by doing an object spread:

return { ...t, done: !t.done }

Another thing worth noting is that our todo now consist of three properties:

title

33
Thinking in Components

done
id

We needed the id property to identify which todo we were trying to modify.

Create a todos component


So far we have everything inside of the App component and we don't want our entire
application to live in there. What if we want to add other stuff. First thing we are going to do
is to create a Todos component and thereby move the rendering, state and methods into
that component. We will end up with the following files:

App.js - we had this from the beginning


Todos.js - this is new

Our Todos.js will contain pretty much all of what App.js used to contain:

// Todos.js

import React, { Component } from 'react';


import styled from 'styled-components';
import PropTypes from 'prop-types';

const TodosContainer = styled.div`


padding: 30px;
`;

const Todo = styled.div`


box-shadow: 0 0 5px gray;
padding: 30px;
margin-bottom: 10px;
`;

class Todos extends Component {


static propTypes = {
todos: PropTypes.array.isRequired,
}

state = {
todos: this.props.todos,
};

handleChecked = (todo) => {


const newTodos = this.state.todos.map(t => {
if (t.id === todo.id) {
return { ...t, done: !t.done };
}
return t;

34
Thinking in Components

});

this.setState({
todos: newTodos,
});
}

render() {
return (
<TodosContainer>
<h2>Todos</h2>
{this.state.todos.map(todo => (
<Todo key={todo.id}>
<input type="checkbox" onChange={() => this.handleChecked(todo)} checked={
todo.done} /> {todo.title}
</Todo>
))}
</TodosContainer>
);
}
}

export default Todos;

The App.js will now look like the following:

35
Thinking in Components

import React, { Component } from 'react';

import Todos from './Todos';

import './App.css';

const todos = [{
title: 'clean',
done: false,
id: 1,
},
{
title: 'do the dishes',
done: true,
id: 2,
}];

class App extends Component {


render() {
return (
<Todos todos={todos} />
);
}
}

export default App;

Breaking down the todos component


So far Todos.js is one massive component. We can break it down according to responsibility.
I mean it works to have it like it is but it's usually better to break down your app into small
focused components, to make maintenance easier. Another reason is making it easier to use
certain components in other places. So what can we break down Todos.js into? Well we can
at least break it down into:

Todos, this would render a list of Todo components and handle all the events
Todo, this would only be responsible for rendering a Todo and send any change action
upwards

Let's make the necessary changes:

36
Thinking in Components

// Todo.js

import React from 'react';


import styled from 'styled-components';
import PropTypes from 'prop-types';

const TodoContainer = styled.div`


box-shadow: 0 0 5px gray;
padding: 30px;
margin-bottom: 10px;
`;

const Todo = ({ todo, handleChecked }) => (


<TodoContainer key={todo.id}>
<input type="checkbox" onChange={() => handleChecked(todo)} checked={todo.done} />
{todo.title}
</TodoContainer>
);

Todo.propTypes = {
todo: PropTypes.shape({
title: PropTypes.string,
done: PropTypes.bool,
id: PropTypes.number,
}),
handleChecked: PropTypes.func,
};

export default Todo;

Above we have broken out the Todo rendering into its own component. As you can see the
component is not defined as a class inheriting from React.Component but is simply just a
function. This is called a presentation or dumb component. What makes it dumb is that it
knows nothing about the context it is in only that it relies on input, todo and invokes any
action that it is being provided through its props, namely handleChecked() . Our Todos file
now looks a bit simpler like so:

37
Thinking in Components

// Todos.js

import React, { Component } from 'react';


import styled from 'styled-components';
import PropTypes from 'prop-types';

import Todo from './Todo';

const TodosContainer = styled.div`


padding: 30px;
`;

class Todos extends Component {


static propTypes = {
todos: PropTypes.array.isRequired,
}

state = {
todos: this.props.todos,
};

handleChecked = (todo) => {


const newTodos = this.state.todos.map(t => {
if (t.id === todo.id) {
return { ...t, done: !t.done };
}
return t;
});

this.setState({
todos: newTodos,
});
}

render() {
return (
<TodosContainer>
<h2>Todos</h2>
{this.state.todos.map(todo => (
<Todo todo={todo} key={todo.id} handleChecked={this.handleChecked} />
))}
</TodosContainer>
);
}
}

export default Todos;

We now import the Todo component, like so:

38
Thinking in Components

import Todo from './Todo';

Let's zoom in on the interesting part:

<Todo todo={todo} key={todo.id} handleChecked={this.handleChecked} />

Above we simply let the Todo component handle all the rendering and we provide it with the
data todo and the method handleChecked() . Ok so we mentioned presentational
components so far so what is the other kind of component the container component. A
container component is a component where data and logic lives. It 'contains' the meat of the
application. In our app the Todos component is a container component and the Todo is a
presentational component. If you are building your app in the right way you will end up with a
majority of presentational components and a few container components.

Summary
We set out to create a working Todo app. We did so. We also set out to break down the
mentioned app into many small components where each component was more focused on
its task making future changes or reuse a lot easier. We introduced the term
Dumb/Presentation component and Container component and explained what those were.
to show that it only relied on inputs.

39
Conditional rendering

Conditional rendering
Conditional rendering is about deciding what to render given a value of a variable. There are
different approaches we can have here:

render if true
ternary expression

Render if true
Let's have a look at the first version:

class Element extends React.Component {

state = {
show: false
};

const toggle = () => {


this.setState({
show: this.state.show
});
}

render() {
return (
<React.Fragment>
<div>some data</div>
{ this.state.show &&
<div>body content</div>
}
<button onClick={this.toggle}></button>
</React.Fragment>
);
}
}

Above we can see that look at the variable show in our state and renders a div if show is
truthy:

{ this.state.show &&
<div>body content</div>
}

40
Conditional rendering

Ternary rendering
In this version we define a ternary expression and render different things depending on the
value of our variable:

class Element extends React.Component {

state = {
loading: false,
data: void 0
};

const toggle = () => {


this.setState({
show: this.state.show
});
}

render() {
return (
<React.Fragment>
{this.state.loading ?
<div>loading...</div> :
<div>{this.state.data}</div>
}
</React.Fragment>
);

}
}

Let's highlight the ternary expression:

{ this.state.loading ?
<div>loading...</div> :
<div>{this.state.data}</div>
}

Using if, else if, else


And of course it is possible to use normal if , else if , else clauses when rendering,
like so:

41
Conditional rendering

class Element extends React.Component {

state = {
loading: false,
data: void 0
};

const toggle = () => {


this.setState({
show: this.state.show
});
}

const click = () => {


this.setState({
loading: true
});
}

getData() {
if (this.state.loading) {
return <div>loading...</div>;
} else if(this.state.data) {
return <div>{this.state.data}</div>;
}
return <div>{this.state.data}</div>;
}

render() {
return (
<React.Fragment>
<div>something</div>
{ this.getData() }
</React.Fragment>
);

}
}

We can't use if , else if and so on directly in the template but we can have a method
getData() that can decide for us what ot render out. Let's highlight what we did above,

define a getData() method with conditional rendering:

42
Conditional rendering

getData() {
if (this.state.loading) {
return <div>loading...</div>;
} else if(this.state.data) {
return <div>{this.state.data}</div>;
}
return <div>{this.state.data}</div>;
}

and calling it in the template like so:

{ this.getData() }

43
Life cycle

Life cycle

componentDidMount
component is mounted and ready to be used

load your data

play with DOM, draw on canvas element.

add event listeners

use case: start AJAX calls here

componentWillReceiveProps
props values are changed and you should react accordingly. do we need to refetch AJAX
data?

verify that change has actually happened and act accordingly. Sometimes React just calls
this so verify that a change has actually taken place.

shouldComponentUpdate
should return true. This is about props changing values and React asking for permission to
change, given that a change has happened. Default answer is true.

You can improve performance here if you know what you are doing. Example of cases
where you wan't to control this, imagine a big table and you only want to change things that
matter.

componentWillUnmount

44
Dealing with input elements

45
Forms

Forms
The default behaviour when submitting a form is form to post the result and move on to
another page. Your markup usually looks like so:

<Form>
<input type="text" name="name" id="name" />
<button>Submit</button>
</Form>

Controlled components
In React however you tend to want to control Forms a bit more. You usually wants to:

verify a form is a valid before being submitted


give error message on input field before submitting so you can correct the answer

You can verify a forms validity by listening to onSubmit() method. That will give you the
form as input and you are able to inspect and determine wether the forms data should be
persisted. It will look like this:

class App extends Component {


onSubmit = (ev) => {
console.log('form', ev.target);

const { name } = ev.target;


// value
console.log('name field', name);
return false;
}

render() {
return (
<div className="App">
<form onSubmit={this.onSubmit}>
<input name="name" id="name" />
<button>Save</button>
</form>
</div>
);
}
}

46
Forms

Single source of truth


The form itself maintains the state of all its input fields but you tend to want to control that
and make React the single source of truth. We can do that by putting each element value in
the state, like so:

class App extends Component {


state = {
firstname: void 0,
}

onSubmit = (ev) => {


console.log('form', ev.target);
return false;
}

handleChange = (ev) => {


this.setState({
firstname: ev.target.value,
});
}

render() {
return (
<div className="App">
<form onSubmit={this.onSubmit}>
<div>
<label>First name</label>
<input name="firstname" id="firstname" value={this.state.firstname} onChan
ge={this.handleChange} />
{this.state.firstname}
</div>
<div>
<button>Save</button>
</div>
</form>
</div>
);
}
}

Above we are creating the method handleChange() that reacts every time the change event
is triggered. We can see that we subscribe to change event when we connect the
handleChange() method to the onChange , like so:

47
Forms

<input name="firstname"
id="firstname"
value={this.state.firstname}
onChange={this.handleChange}
/>

Adding more input elements


So far we have seen how we can add an input element and hook up a method to onChange
and stick the value of the element into the state object. Does this means we will have 20
different methods if we have 20 different inputs? No, we can solve this in an elegant way:

48
Forms

class App extends Component {


state = {
firstname: void 0,
lastname: void 0,
}

onSubmit = (ev) => {


console.log('form', ev.target);
return false;
}

handleChange = (ev) => {


this.setState({
[ev.target.name]: ev.target.value,
});
}

render() {
return (
<div className="App">
<form onSubmit={this.onSubmit}>
<div>
<label>First name</label>
<input name="firstname" id="firstname" value={this.state.firstname} onChan
ge={this.handleChange} />
{this.state.firstname}
</div>
<div>
<label>Last name</label>
<input name="lastname" id="lastname" value={this.state.lastname} onChange=
{this.handleChange} />
{this.state.lastname}
</div>
<div>
<button>Save</button>
</div>
</form>
</div>
);
}
}

Let's zoom in on the interesting part:

handleChange = (ev) => {


this.setState({
[ev.target.name]: ev.target.value,
});
}

49
Forms

We replaced setting a specific key by name, firstname in this case, to a more generic
variant [ev.target.name] . This will enable us to hook up the handleChange() method to any
input of the same type.

Radio buttons and check boxes


Radio button usually have the behaviour that we want one radio button out of many
selected. To accomplish that we ensure all radio buttons that belong together have the same
name. We therefore create a markup looking like this:

<div>
Man <input type="radio" name="weather" value="sunshine" onChange={this.handleChang
e} />
Woman <input type="radio" name="weather" value="rain" onChange={this.handleChange}
/>
</div>

As we can see above we can easily attach the handleChanged() method to the onChange .

What about check boxes? Well for checkboxes you can select several different ones, if you
check a checkbox then a checkbox of the same group shouldn't be deselected, unlike a
radio button. Checkboxes are a little bit different in nature as they require us to look at the
property checked instead of value. Let's have a look at their markup:

<div>
Yellow <input type="checkbox" name="yellow" id="yellow" value={this.state.yellow}
onChange={this.handleChange} />
</div>
<div>
Blue <input type="checkbox" name="blue" id="blue" value={this.state.yellow} onChan
ge={this.handleChange} />
</div>
<div>
Red <input type="checkbox" name="red" id="red" value={this.state.yellow} onChange={
this.handleChange} />
</div>

As mentioned we need to look at the property checked , this means we need to alter the
method handleChange() slightly, to this:

50
Forms

handleChange = (ev) => {


const value = ev.target.type === 'checkbox' ? ev.target.checked : ev.target.value;

this.setState({
[ev.target.name]: value,
});
}

From the above code we see that we inspect to see wether target.type is of type
checkbox , if so we look at the checked property to find our value.

Select list
Select lists are quite easy, we can construct those using a select tag and many option
tags, like so:

{this.state.products.length > 0 &&


<select name="product" onChange={this.handleChange}>
{this.state.products.map(p => (
<option selected={this.state.product === p} value={p}>{p}</option>
))}
</select>
}

Above we simply repeat out a list of products and set the value property and the inner
HTML of the option element. We also set the selected property if our
this.state.product corresponds to the rendered out element.

51
Forms II - validation

Forms II - validation
Validating forms can be done in different ways:

Validate an element as soon as you type, and immediately indicate any error
Validate the form on pressing submit

Validate an element
You can have all the elements and their validation in one giant component but it is usually
better to create a dedicated component for this. A component like this should have the
following:

render the element itself, this will give us more control over how the element is rendered
an element where you can output the validation error
a way to listen to changes and validate itself while the user types
a way to indicate to the form that it is no longer valid should a validation error occur

Render the element


With this one we mean that we need to create a component around our element. To do so is
quite simple:

import React from 'react';

class Input extends React.Component {


render() {
return (
<input { ...this.props} />
);
}
}

As you can see above we make the Input component render an input element tag. We
also ensure that all properties set on the component make it to the underlying input by typing
{ ...this.props} . A more manual version of the last one would be to type:

<input title={this.props.title} value={this.props.value} ... >

52
Forms II - validation

Depending on how many attributes we want to send to the underlying input, it could be quite
a lot of typing.

As we are now in control of how the input is rendered we can do all sorts of things like
adding a div element, give it padding, margin, borders etc. Best part is we can reuse this
component in a lot of places and all of our inputs will look nice and consistent.

Adding validation
Now we will see that it pays off to wrap our input element in a component. Adding
validation to our element is as easy as:

add element placeholder where your error should be shown


add a function that validates the input value
validate on every value change, we need to add a callback to onChange

Render the error


Alter the render() method to the below:

render() {
return (
<InputContainer>
{this.state.error &&
<ErrorMessage>{this.state.error}</ErrorMessage>
}
<div>
{this.props.desc}
</div>
<InnerInput value={this.state.data} onChange={this.handleChange} {...this.props}
/>
</InputContainer>
);
}

Here we are conditionally displaying the error message, assuming its on the state:

{this.state.error &&
<ErrorMessage>{this.state.error}</ErrorMessage>
}

We are also hooking up a handleChange() method to onChange .

Adding validation function

53
Forms II - validation

Next step is adding our validation function:

const validate = (val, errMessage) => {


const valid = /^[0-9]{2,3}$/.test(val);
return valid ? '' : errMessage;
};

Our function above simply tests wether our input value matches a RegEx pattern and if so its
valid, if not, then we return the error message.

Managing the state


So who is calling this function? Well the handleChange() method is, like so:

handleChange = (ev) => {


const { errMessage } = this.props;

const error = validate(ev.target.value, errMessage);


this.setState({
data: ev.target.value,
error,
});
}

We do two things here, firstly we call validate() to see if there was an error and secondly
we set the state, which is our value and the error. If the error is an empty string then it is
counted as falsy . So we can always safely set the error property and any error message
would only be visible when it should be visible.

The full code for our component so far looks like this:

import React from 'react';


import styled from 'styled-components';
import PropTypes from 'prop-types';

const InnerInput = styled.input`


font-size: 20px;
`;

const InputContainer = styled.div`


padding: 20px;
border: solid 1px grey;
`;

const ErrorMessage = styled.div`


padding: 20px;
border: red;

54
Forms II - validation

background: pink;
color: white;
`;

const validate = (val, errMessage) => {


const valid = /^[0-9]{2,3}$/.test(val);
return valid ? '' : errMessage;
};

class Input extends React.Component {


static propTypes = {
name: PropTypes.string,
desc: PropTypes.string,
errMessage: PropTypes.string,
};

state = {
error: '',
data: '',
}

handleChange = (ev) => {


const { errMessage, name } = this.props;

const error = validate(ev.target.value, errMessage);


this.setState({
data: ev.target.value,
error,
});
}

render() {
return (
<InputContainer>
{this.state.error &&
<ErrorMessage>{this.state.error}</ErrorMessage>
}
<div>
{this.props.desc}
</div>
<InnerInput value={this.state.data} onChange={this.handleChange} {...this.props
} />
</InputContainer>
);
}
}

export default Input;

Telling the form

55
Forms II - validation

Usually when you put input elements in a form you want to be able to tell the form that one
or more invalid inputs exist and you want the stop the form from being submitted. To do so
we need send a message to our form every time a value changes and if there is a validation
error, the form will know. To accomplish that we need to do the following:

add a notify input property, this will be a function we can call as soon as we validated
the latest change
call the notify function

We there update our handleChange() method to now make a call to the notify() function
that we pass in, like so:

handleChange = (ev) => {


const { errMessage, name, notify } = this.props;

const error = validate(ev.target.value, errMessage);


notify(name, error === '');
this.setState({
data: ev.target.value,
error,
});
}

notify() is called with two params, name and wether it is valid.

Setting up the form


Ok great, we have a way to communicate errors back to the form, what about the form itself,
what does it need to do for this to work? It needs the following:

a method that it can hook up the notify property


determine what to do if one or more elements are invalid, like for example disable the
submit button

We decide on creating a dedicated component for our form as well:

56
Forms II - validation

import React from 'react';


import styled from 'styled-components';
import Input from './Input';

const FormContainer = styled.form`


border: solid 2px;
padding: 20px;
`;

class Form extends React.Component {


state = {
isValid: true,
}

notify = (name, isValid) => {

render() {
return (
<FormContainer>
<div>
<Input
errMessage="Must contain 2-3 digits"
desc="2-3 characters"
name="first-name"
notify={this.notify}
title="I am a custom inbox" />
</div>
<button>Submit</button>
</FormContainer>
);
}
}

export default Form;

At this point we have hooked up our notify input property to a method on our component
called notify() , like so:

<Input
errMessage="Must contain 2-3 digits"
desc="2-3 characters"
name="first-name"
notify={this.notify}
title="I am a custom inbox"
/>

As you can see our notify() method doesn't do much yet, but it will:

57
Forms II - validation

notify = (name, isValid) => {}

So what do we need to accomplish with a call to notify() ? The first thing we need to
accomplish is telling the form that one of your inputs is invalid. The other is to set the whole
form as invalid. Based on that we define our notify() code as the following:

notify = (name, isValid) => {


this.setState({
[name]: isValid,
}, () => {
this.setState({
isValid: this.validForm(),
});
});
}

We see above that we after having updated our state for our input element we set the state
for isValid and call the method validForm() to determine its value. The reason for setting
the isValid state like this is that setState() doesn't happen straight away so it is only in
the callback that we can guarantee that it's state has been updated.

isValid is the property we will use in the markup to determine wether our form is valid.

Let's define the method validForm() next:

validForm = () => {
const keys = Object.keys(this.state);
for (let i = 0; i < keys.length; i++) {
if (keys[i] === 'isValid') { continue; }

if (!this.state[keys[i]]) {
return false;
}
}

return true;
}

Above we are looping through our state and is looking for wether one of the input elements
are invalid. We skip isValid as that is not an element state.

Determine form state


We have now set everything up to make it easy to indicate wether the form can be submitted
or not. We can handle that in two ways:

58
Forms II - validation

disabling the submit button


let the user press the submit button but stop the submit from going through

If we do the first variant we only need to change the markup to the following:

render() {
return (
<FormContainer onSubmit={this.handleSubmit}>
<div>
<Input
errMessage="Must contain 2-3 digits"
desc="2-3 characters"
name="first-name"
notify={this.notify}
title="I am a custom inbox"
/>
</div>
<button disabled={!this.state.isValid}>Submit</button>
</FormContainer>
);
}

Let's zoom in on the interesting bit:

<button disabled={!this.state.isValid}>Submit</button>

We read from our isValid property and we are to disable our button when we want.

The other version of stopping the submit from going through involves us adding some logic
to the method handleSubmit() :

handleSubmit = (ev) => {


ev.preventDefault();

if (!this.state.isValid) {
console.log('form is NOT valid');
} else {
console.log('valid form')
}
}

59
Formik - part II

Follow me on Twitter, happy to take your suggestions on topics or improvements /Chris

This is the continuation of our first part on Formik, the amazing Forms library for React

This article is part of series:

No more tears, handling Forms in React using Formik, part I


No more tears, handling Forms in React using Formik, part II, we are here

In this article we will cover:

Schema Validation with Yup, there is an alternate way to validate your input elements
and that is by declaring a schema in Yup and simply assign that to an attribute on the
Formik component
Async validation
Built in components, make everything less verbose using some of Formiks built-in
components

Built in components
So far we have been using regular HTML elements like form and input to build our form
and we have connected to events like onSubmit , onChange and onBlur . But we can
actually be typing a lot less. Say hello to the following components:

Form, this replaces a normal form element

60
Formik - part II

Field, this replaces any type of input element


ErrorMessage, this doesn't really replace any controls that you have but is a great
component that given the attribute name is able to show your error message

Let's first look at a simple form and then rewrite it using the above-mentioned components:

import Formik from 'formik';


import React from 'react';

const FormikExample = () => (


<Formik
initialValues={{ name: '' }}
validation={values => {
let errors = {};
if(!values.name) {
errors.name = 'Name is required';
}
return errors;
}}
onSubmit={values ={
console.log('submitted');
}}
>
{({ handleSubmit, handleChange, values, errors }) => (
<form onSubmit={handleSubmit}>
<input name="name" onChange={handleChange} value={values.name} />
{errors.name &&
<span>{errors.name}</span>
}
</form>
)
}
</Formik>
)

Ok, above we see what a minimal implementation looks like the classical way of doing it,
that is using HTML elements like form and input .

Now lets clean this up using Formiks built in controls:

61
Formik - part II

import Formik from 'formik';


import React from 'react';

const FormikExample = () => (


<Formik
initialValues={{ name: '' }}
validation={values => {
let errors = {};
if(!values.name) {
errors.name = 'Name is required';
}
return errors;
}}
onSubmit={values ={
console.log('submitted');
}}
>
{({ handleSubmit, errors }) => (
<form onSubmit={handleSubmit}>
<Field type="text" name="name" />
<ErrorMessage name="name"/>
}
</form>
)
}
</Formik>
)

Not super impressed? Let's list what we don't need to type anymore:

the onChange disappears from each input element


the input element is replaced by Field component
the form element is replaced by Form component
the conditional {errors.name && disappears as well as ErrorMessage component takes
care of that bit

Not enough? Well imagine you have 10 fields, that is at least 10 lines of code that
disappears and it generally it just looks cleaner. Now to our next improvement, we can
replace our validation() function with a schema , up next.

Schema validation with Yup


Ok, we've covered how we can really clean up our markup by using the builtin controls
Form , Field and ErrorMessage . Next step is improving even more by replacing our

validation property with a validationSchema property. For that to be possible we need to

define a schema using the library Yup. So what does a schema look like :

62
Formik - part II

import * as Yup from 'yup'

const schema = Yup.object().shape({


firstName: Yup.string()
.min(2, 'Too Short!')
.max(50, 'Too Long!')
.required('Required'),
lastName: Yup.string()
.min(2, 'Too Short!')
.max(50, 'Too Long!')
.required('Required'),
email: Yup.string()
.email('Invalid email')
.required('Required'),
});

The above schema defines three different fields firstName , lastName and email and
gives them each attributes that they should adhere to:

firstName, this should be a string consisting of min 2 characters and maximum 50


characters and its also required
lastName, this is also a string with the same min/max requirements and it's also
required
email, this is just a string that is required

As you can see the above is quite readable and by defining your data like this you save
yourself from having to type a lot of if constructs checking if all attributes are fulfilled.

Let's now put it to use in our Formik element, like so:

<Formik validationSchema={schema}>

That's it, that is all you need to define your form data in a really expressive way, doesn't that
give you a warm and fuzzy feeling? :)

Async validation

63
Formik - part II

Ok, now to our last topic, asynchronous validation. So what's the scenario? Well sometimes
you have data that you can't really tell on client side only wether the entered value is correct
or not. Imagine you have a form where you want to find out wether a company or certain
web page domain is already taken? At that point you most likely will need to make a call to
an endpoint and the endpoint will not be coming back with the answer instantly.

Ok, we've set the scene, how do we solve this in Formik? Well, the validation property is
able to accept a Promise as well. Really, you think? That easy? Well the solution is in my
mind a bit unorthodox, let me show you what I mean:

<Formik
validate={values => {
console.log('validating async');
let errors = {};
return new Promise((resolve, reject) => {
setTimeout(() => {
errors.companyName = 'not cool';
resolve('done');
},3000);
}).then(() => {
if(Object.keys(errors).length) {
throw errors;
}
});
}}
>
// define the rest here
</Formik>

Looking at our validate implementation we see that we create a Promise that internally
runs a setTimout to simulate it going to an endpoint that it takes time to get an answer
from. At this point we set a errors.companyName to an error text:

setTimeout(() => {
errors.companyName = 'not cool';
resolve('done');
},3000);

In more real scenario we would probably call a function and depending on the functions
answer we would possibly assign errors.companyName . I'll show you below what I mean:

64
Formik - part II

isCompanyNameUnique(values.companyName).then(isUnique => {
if(!isUnique) {
errors.companyName = `companyName is not unique, please select another one`
}
resolve('done')
})

Next thing that happens in our code is that we invoke then() , that happens when we call
resolve() . Something really interesting happens in there, we check the errors for any

properties that might have been set and if so we throw an error with our errors object as
argument, like so:

.then(() => {
if(Object.keys(errors).length) {
throw errors;
}
});

I don't know about you, but to me, this looks a bit weird. I would have thought providing
validation with a Promise would have meant that a reject() of the Promise would have

been a more intuitive way of doing it, like so:

// this to me would have been more intuitive, but observe, this is NOT how it works, s
o DONT copy this text but refer to the above code instead

validation={ values =>


console.log('validating async');
let errors = {};
return new Promise((resolve, reject) => {
setTimeout(() => {
errors.companyName = 'not cool';
reject(errors);
},3000);
})
}}

Async on field level


So far we have shown how to do async validation on Forms level but if you think about
would you really want that? Most likely you have a mix of fields where it's enough to validate
some of them client side while only a minority if fields needs async validation. In such a case
it makes sense to apply validation per field. That is quite easy to achieve by typing like this:

<Field name="username" validate={this.validate} >

65
Formik - part II

This is probably preferred if you got async validation on a field. As for the other fields you
can validate client side it's probably a good idea to define those in on the Formik
components validationSchema and use Yup schemas for that like we've described above.

Words of caution
If we do have async validation in there make sure your validations don't run too often
especially if the validation takes time. You don't want a 3 sec validation to trigger every time
a key is typed, at most you want it when the user leaves the field to start typing in another
field, we refer to this as the blur event. So make sure you set up your Formik component
like this:

<Formik
validateOnBlur={true}
validateOnChange={false} >

This does what you want, setting validateOnBlur to true is what you want, even though
techinally this is true by default. You want to be explicit with the next one though
validateOnChange . You want this to be off, or set to false .

Summary
We've set out to cover built-in components like Form , Field and ErrorMessage , the end
result was us cleaning up a lot of code.

Furthermore we showed how we could get rid of our validation function by defining a
schema using the Yup library.

Finally we covered asynchronous validation and we discussed things to consider like when
to validate and that it is probably best to have a field level validation for those few
asynchronous fields that we have in a form and to use schema validation for the remaining
fields.

That's it, that was the end of our article. I hope this part and the previous one have given you
new hope that dealing with Forms in React doesn't have to that painful

66
Formik - part II

67
AJAX /HTTP

68
styled-components

Styled components
There are a ton of ways to style components in React. This is probably my favourite way of
doing it and it differs somewhat conceptually from other ways of styling.

The case for the styled components approach


When you start out styling your React components you may opt for defining CSS classes
and assigning them to each element, like so:

<div className="card">
<div className="card-header">
<h3>{card.header}</h3>
</div>
<div className="content">{card.content}</div>
</card>

There is really nothing wrong with the above, it is a viable approach even though some of
you might think that's a lot of repeated typing of the word className .

You can argue at this point that I can create component for the card, the card header and
the card component respectively. Yes we can do that. Then it might look like this instead:

<card header={card.header}>
{card.content}
</card>

However these components are likely to be quite simple and only just render their child
element. So what you need to ask yourself is do I really need a component for that, when all
I want to do is add some CSS styling and name my HTML element what I please? If this is
where your thoughts are heading then maybe styled-components library might be for you?

Installing and setting up styled-components


We can simple install styled-components via NPM, like so:

yarn add styled-components


OR
npm install --save styled-components

69
styled-components

After this we are ready to go and use it in our React project.

Our first styling


The example the homepage for this library uses is that of buttons. You might end up creating
different buttons meant for different purposes in your app. You might have default buttons,
primary buttons, disabled buttons and so on. Styled components lib enable you to keep all
that CSS in one place. Let's start off by importing it:

import styled from 'styled-components';

Now to use it we need to use backticks `, like so:

const Button = styled.button``;

At this point we don't have anything that works bit it shows you the syntax.

As we can see above we call styled.nameOfElement to define a style for our element. Let's
add some style to it:

const Button = styled.button`


background: black;
color: white;
border-radius: 7px;
padding: 20px;
margin: 10px;
font-size: 16px;
:disabled {
opacity: 0.4;
}
:hover {
box-shadow: 0 0 10px yellow;
}
`;

What we can see from the above example is that we are able to use normal CSS properties
in combination with pseudo selectors like :disabled and :hover .

If we want to use our Button as part of our JSX we can simply do so, like so:

70
styled-components

<div>
<Button>
press me
</Button>
</div>

We can intermix our Button with all the HTML or JSX that we want and we can treat it just
like the HTML element button , because it is one, just with some added CSS styling.

Using attributes
The styled-component library can apply styles conditionally by looking for the occurrence of
a specified attribute on our element. We can use existing attributes as well as custom ones
that we make up.

Below we have an example of defining a primary button. What do we mean with primary
versus a normal button. Well in an application we have all sorts of buttons, normally we have
a default button but we have also a primary button, this is the most important button on that
page and usually carries out things like saving a form.

It's a quite common scenario to style a primary button in a different way so we see a
difference between such a button and a normal button so the user understands the gravity of
pushing it.

Let's now show how we design such a button and showcase the usage of attributes with
styled-components . We our styled Button the attribute primary , like so:

<Button primary >I am a primary button</Button>

Our next step is updating our Button definition and write some conditional logic for if this
attribute primary is present.

We can do so with the following construct:

${props => props.primary && css`

`}

We use the ${} to signal that we are running some conditional logic and we refer to
something called props . props is simple a dictionary containing all the attributes on our
element. As you can see above we are saying props.primary is to be truthy, it is defined in

71
styled-components

our attributes dictionary. If that is the case then we will apply CSS styling. We can tell the
latter from the above code through our use of css function.

Below we use the above construct add some styling that we should only apply if the
primary attribute is present:

const Button = styled.button`


background: black;
color: white;
border-radius: 7px;
padding: 20px;
margin: 10px;
font-size: 16px;
:disabled {
opacity: 0.4;
}
:hover {
box-shadow: 0 0 10px yellow;
}

${props => props.primary && css`


background: green;
color: white;
`}
`;

Now we have a more full example of how to test for the existence of a particular attribute.
Just one note, we said we needed to use the css function. This is a function that we find in
the styled-components namespace and we can therefore use it by updating our import
statement to look like this:

import styled, { css } from 'styled-components';

Adapting
We've shown how we can look at if certain attributes exist but we can also set different
values on a property depending on wether an attribute exist.

Let's have a look at the below code where we change the border-radius depending wether
a circle attribute is set:

72
styled-components

const Button = styled.button`


background: black;
color: white;
border-radius: 7px;
padding: 20px;
margin: 10px;
font-size: 16px;
:disabled {
opacity: 0.4;
}
:hover {
box-shadow: 0 0 10px yellow;
}

${props => props.primary && css`


background: green;
color: white;
`}

border-radius: ${props => (props.round ? '50%' : '7px')}


`;

The interesting bit of the code is this:

border-radius: ${props => (props.round ? '50%' : '7px')}

We can trigger the above code to be rendered by declaring our Button like so:

<Button round >Round</Button>

Styling an existing component


This one is great for styling 3rd party components or one of your own components. Imagine
you have the following components:

73
styled-components

// Text.js
import React from 'react';
import PropTypes from 'prop-types';

const Text = ({ text }) => (


<div> Here is text: {text}</div>
);

Text.propTypes = {
text: PropTypes.string,
className: PropTypes.any,
};

export default Text;

Now to style this one we need to use the styled function in a little different way. Instead of
typing "styled``" we need to call it like a function with the component as a parameter like so:

const DecoratedText = styled(Text)`


// define styles
`;

<DecoratedText text={"I am now decorated"} />

In the component we need to take the className as a parameter in the props and assign
that to our top level div, like so:

// Text.js
import React from 'react';
import PropTypes from 'prop-types';

const Text = ({ text, className }) => (


<div className={className}> Here is text: {text}</div>
);

Text.propTypes = {
text: PropTypes.string,
className: PropTypes.any,
};

export default Text;

As you can see above calling the styled() function means that it under the hood produces
a className that it injects into our component that we need to set to our top level element,
for it to take effect.

74
styled-components

Inheritance
We can easily take an existing style and add to it by using the method extend, like so:

const GiantButton = Button.extend`


font-size: 48px;
`;

Change styled components


In some cases you might want to apply the style intended for a specific type of element and
have that applied to another type of element. A common example is a button.You might like
all the styling a specific button comes with but you might want to apply that on an anchor
element instead. Using the withComponent() method allows you to do just that:

const LinkButton = Button.withComponent('a');

The end result of the above operation is an anchor,a tag with all the styling of a Button.

Using the attribute function


Sometimes all you need is just to change a small thing in the component styling. For that the
attrs() function allows you to add a property with a value. Let's illustrate how we can add

this:

const FramedText = styled(Text).attrs({ title: 'framed' })`


border: solid 2px black;
color: blue;
font-size: 16px;
padding: 30px;
`;

Above we have chained styled() and attrs() and we end with a double ` tick. Another
example is:

75
styled-components

const Button = styled.button.attrs({ title: 'titled' })`


background: black;
color: white;
border-radius: 7px;
padding: 20px;
margin: 10px;
font-size: 16px;
:disabled {
opacity: 0.4;
}
:hover {
box-shadow: 0 0 10px yellow;
}

${props => props.primary && css`


background: green;
color: white;
`}

border-radius: ${props => (props.round ? '50%' : '7px')}


`;

Theming
Styled components exports a ThemeProvider that allows us to easily theme our styled
components. To make it work we need to do the following:

import the ThemeProvider


set it as root Element of the App
define a theme
refer to a property in theme and set that to desired CSS property

Set up
In the component where we intend to use a Theme we need to import and declare a
ThemeProvider . Now this can be either the root element of the entire app or the component

you are in. ThemeProvider will inject a theme property inside of either all components or
from the component you add it to and all its children. Let's look at how to add it globally:

ReactDOM.render(
<ThemeProvider theme={{ color: 'white', bgcolor: 'red' }}>
<App />
</ThemeProvider>,
document.getElementById('root'),
);

76
styled-components

Now we are ready to change our components accordingly to start using the theme we set
out:

Let's take the Button component that we defined and have it use our theme, like so:

const Button = styled.button.attrs({ title: 'titled' })`


background: ${props => props.theme.bgcolor};
color: ${props => props.theme.color};
border-radius: 7px;
padding: 20px;
margin: 10px;
font-size: 16px;
:disabled {
opacity: 0.4;
}
:hover {
box-shadow: 0 0 10px yellow;
}

${props => props.primary && css`


background: green;
color: white;
`}

border-radius: ${props => (props.round ? '50%' : '7px')}


`;

Let's zoom in on what we did:

background: ${props => props.theme.bgcolor};


color: ${props => props.theme.color};

As you can see we are able to access the themes property by writing props.theme.
<nameOfThemeProperty> .

Theme as a higher order component factory


If we want to use the theme inside of a component we can do so but we need to use a
helper called withTheme() . It takes a component and the theme property to it, like so:

77
styled-components

import { withTheme } from 'styled-components';

class TextComponent extends React.Component {


render() {
console.log('theme ', this.props.theme);
}
}

export default withTheme(TextComponent);

Summary
We have introduced a new way of styling our components by using the styled-components
library.

We've also learned that we get a more semantic looking DOM declaration of our
components when we compare it to the classical way of styling using className and
assigning said property CSS classes.

Further reading
The official documentation provides some excellent example of how to further build out your
knowledge styled-components official documentation

Hopefully this has convinced you that this is a good way of styling your React components.
Since I found this library this is all I ever use, but that's me, you do you :)

If you found this useful please give me a clap

My twitter

My free book on React Free book

78
inline styling

Inline styling
React has a different take on styling. You can definitly set a style tag with content. However,
what you set to it needs to be an object with properties in it and the properties needs to have
pascal casing. Let's show how this can look:

import image from './image.jpg';

const styles = {
color: 'red',
backgroundImage: `url(${url})`
};

class TestComponent extends React.Component {


render() {
return (
<div style={styles}>style this</div>
);
}
}

Note the use of backgroundImage we have to write it like that rather than background-image .

Working with CSS files


We can of course work with normal CSS files. We can define our styles in there and just
import the file, like so:

// App.css

.container {
font-size: 16px;
border: solid 1px black;
}

To use it we simply do an import , like so:

79
inline styling

import './App.css';

class TestComponent {
render() {
return (
<div className={container}></div>
);
}
}

Note in the above code that we are using the attribute className to set a CSS class. By
using the import above our component can now freely use the CSS specified in App.css .

80
sass/less

81
Adding images

Adding images
So how do we deal with images that we have locally. It's really very easy, we just need to
import and assign them to the source property of our image, like so:

import myImage from './assets/myImg.png';

class TestComponent extends React.Component {


render() {
return (
<img src={myImage} />
);
}
}

So why does this work, well here is an explanation from the official docs:

...You can import a file right in a JavaScript module. This tells Webpack to include that
file in the bundle. Unlike CSS imports, importing a file gives you a string value. This
value is the final path you can reference in your code, e.g. as the src attribute of an
image or the href of a link to a PDF.

To reduce the number of requests to the server, importing images that are less than
10,000 bytes returns a data URI instead of a path. This applies to the following file
extensions: bmp, gif, jpg, jpeg, and png...

82
Core concepts

Routing

Type of routers
BrowserRouter
HashRouter
Router

Install and set up


Installing the router

npm install --save react-router-dom

Adding the router

// index.js

import { BrowserRouter } from 'react-router-dom'

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

Defining the routes


Our routes will be defined by x number of Route element where we specify which path
they will match and what component that should respond. All these routes will be put inside
of a Switch component. It will look like the following:

83
Core concepts

// Main.js

import React, { Component } from 'react';


import { Switch, Route } from 'react-router-dom';

import Home from './Pages/Home';


import Products from './Pages/Products';
import ProductDetail from './Pages/ProductDetail';

const Main = () => (


<main>
<Switch>
<Route exact path='/' component={Home}/>
<Route exact path='/products' component={Products}/>
<Route path='/products/:id' component={ProductDetail}/>
</Switch>
</main>
);

export default Main;

Worth noting above is our usage of the attribute exact , without it our router wouldn't be
able to tell the difference between /products and /products/:id . Removing it will lead to a
product list being loaded even when we type /products/111 . Why is that? The way the
router is constructed it will match the first pattern it sees. Because we are a bit relaxed on
the rules, that is a router containing /products . The following Route :

<Route exact path='/products' component={Products}/>

Will match /products and /products/114 . To fix this we re-add the exact attribute and
suddenly it will only match /products . This means to match /products/111 it needs to
keep looking in our route definition tree and it will find the following to match it:

<Route path='/products/:id' component={ProductDetail}/>

As expected it now loads our product detail view instead.

Set up the app


Now that we have installed the library. Set up a route dictionary it's time to talk about how we
would define the skeleton of our app. Normally an app has a header and a body. So our
App.js file will now look like this:

84
Core concepts

import React, { Component } from 'react';


import Main from './Main';
import Head from './Head';

import logo from './logo.svg';


import './App.css';

class App extends Component {


render() {
return (
<React.Fragment>
<Head />
<Main />
</React.Fragment>
);
}
}

export default App;

We have already defined what the Main component looks like above in Main.js. What about
Head component? Well this is typically where we define a menu the user can interact with.

This is where we introduce the Link component. This will help us create links that our
router knows how to respond to. Ultimately it will generate anchor, a -tags.

85
Core concepts

// Head.js

import React, { Component } from 'react';


import styled from 'styled-components';
import { Link } from 'react-router-dom'

const Menu = styled.div`


box-shadow: 0 2px 2px;
border-bottom: solid 1px grey;
padding: 20px;
margin-bottom: 20px;
`;

const MenuItem = styled(Link)`


padding: 20px 10px;
`;

const Head = () => (


<Menu>
<MenuItem to="/" >Home</MenuItem>
<MenuItem to="/products" >Products</MenuItem>
</Menu>
);

export default Head;

86
Dealing with router and query params

Dealing with router and query params


There are two different concepts that interest us, the first is router parameters and the
second is query parameters. What are these concepts? A router parameter is part of your url
and can look like the following:

/products/111
/users/1/products

Router params
In the first case we query against a resource /products and is looking for a particular item
111 .

In the second case we are looking at the resource users and the specific user with id
having value 1 .

So router parameters are part of your url. Usually what we do is having a user navigate to a
page and if necessary we dig out the router parameter, cause it needs to be part of our
query. Imagine that the link /products/111 is clicked. This will mean we will take the user to
a ProductDetail component where we will need to:

dig out the the router param


pose a query based on said param and show the result

87
Dealing with router and query params

class ProductDetail extends React.Component {


state = {
product: void 0
}

async componentDidMount() {
const product = await api.getProduct(`/products/${this.props.match.params.id}`);
this.setState({
product,
});
}

render() {
return (
<React.Fragment>
{this.state.product &&
<div>{this.state.product.name}</div>
}
</React.Fragment>
);
}
}

The interesting part here being how we access the router parameter:

this.props.match.params.id

There is a match object that contains a params object that points to our router parameter
id .

Let's quickly remind ourself how this router was set up:

<Route path='/products/:id' component={ProductDetail}/>

Above you can see that we define the route /products/:id , and thereby we set the wildcard
to :id , which makes it possible for us to access it in code by typing
this.props.match.params.id .

Query params
Let's talk about query parameters next. A query parameter is used to filter down a resource.
A typical example is using parameters like pageSize or page to indicate to the backend
that you only want a small slice of content and not the full list which can be millions of rows

88
Dealing with router and query params

potentially. Query parameters are found after the ? character in the url which would make
the url look like this /products?page=1&pageSize=20 . Let's have a look in code how we can
access query parameters:

import React from 'react';


import { parse } from 'query-string';

class Products extends React.Component {


state = {
products: []
};

async componentDidMount() {
const { location: { search } } = this.props;
const { page, pageSize } = search;

const products = await api.getProducts(`/products?page=${page}&pageSize=${pageSize}


`);
this.setState({
products,
});
}

render() {
<React.Fragment>
{this.props.products.map(product => <div>{product.name}</div>)}
</React.Fragment>
}
}

As you can see above we are able to access our query parameters through a location
object that sits on a search object that represents our parameters like so:

{
page: 1
pageSize: 20
}

89
Programmatic navigation

Programmatic navigation
Usually we navigate using the Link component but sometimes we need to navigate based
on an action. Then we are talking about programmatic navigation. There are essentially two
ways of making that happen:

history.push('url')
Redirect component

Using history
To use the first one we need to inject the history inside of our component. This is
accomplished by using withRouter() function. Below is an example of a component using
the described:

import React from 'react';


import { withRouter } from 'react-router-dom';

class TestComponent extends React.Component {


navigate= () => {
this.props.history.push('/');
}

render() {
return (
<React.Fragment>
<button onClick={this.navigate}>Navigate</button>
</React.Fragment>
);
}
}

export default withRouter(TestComponent);

Using redirect component


Using Redirect component is a different approach but just as valid. The idea is to have it
look at a state in the component and if that condition is fulfilled then navigate. Here is how it
could look like in code:

90
Programmatic navigation

import { Redirect } from 'react-router';

// this could be from a React context or a Redux store


import { loggedIn } from './login';

const User = () => (


<div>username ... </div>
);

class UserDetail extends React.Component {


render() {
<React.Fragment>
{isLoggedIn() ? <User /> : <Redirect to='/login' /> }
</React.Fragment>
}
}

91
Dealing with lazy loading/ code splitting

Lazy loading
Oftentimes building an app the resulting bundle tend to be fairly large as our project grows in
size. This will affect the loading time of our app for users on connections with low bandwidth,
mobile users for example. For that reason it's a good idea to only load as much of your
application as you need.

What do we mean by that? Imagine your application consists of many many routes. Some
routes you are likely to be visited often and some not so much. If you instruct your app to
only load the routes the user really needs, at first load, then you can load in more routes as
the user asks for them. We call this lazy loading. We are essentially creating one bundle that
constitutes our initial application then many small bundles as we visit a specific route. We
will need Webpack and React to work together on accomplishing this one.

Let's start by having a look at what our routes currently look like:

import React from 'react';


import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Home from './Home';
import Contact from './Contact';
import Products from './Products';

const home = () => import('./Home/index');


const contact = () => import('./Contact/index');

const Products = () => (


<div>Products</div>
);

const Main = () => (


<Router>
<Switch>
<Route path='/' exact={true} component={Home} /> } />
<Route path='/' exact={true} component={Contact} /> } />
<Route path='/' exact={true} component={Products} /> } />
</Switch>
</Router>
);

export default Main;

We can use the import function to help us import a component when we need it and
thereby accomplishing a lazy load behaviour, like so:

92
Dealing with lazy loading/ code splitting

import('./Home')

Though this isn't quite enough.

Why? This returns a Promise . Not only that, it's not a valid React child so we need to stick it
into a component. For that reason we write a component whose job it is to retrieve the result
and ensure we render out our fetched component, like so:

class Async extends React.Component {


state = {
Component: void 0
};

async componentDidMount() {
const res = await this.props.provider();
this.setState({ Component: res.default });
}

render() {
const { Component } = this.state;
return(
<React.Fragment>
{Component ? <Component /> : <div>Loading...</div>}
</React.Fragment>
)
}
}

Now we can set up a route like so:

<Route path='/products' exact={true} component={() => <Async provider={() => import('.


/Products/Products')} />} />

However this doesn't look quite nice though, we are accessing the default property of our
import and /Products/Products as route could look better. It would be nicer if we could
define our import url as /Products and be able to avoid accessing the default import. We do
need to alter the component directory a bit from:

/Products
Products.js

to

93
Dealing with lazy loading/ code splitting

/Products
Products.js
index.js

In our newly created index.js we can import our component and export it, like so:

// Products/index.js

import Products from './Products';


export const Component = Products;

Let's head back to Main.js and change the Async component to this:

class Async extends React.Component {


state = {
Component: void 0
};

async componentDidMount() {
const { Component } = await this.props.provider();
this.setState({ Component });
}

render() {
const { Component } = this.state;
return(
<React.Fragment>
{Component ? <Component /> : <div>Loading...</div>}
</React.Fragment>
)
}
}

The big difference here is getting our component like this const { Component } = await
this.props.provider() . Now let's update how we set up the route to this:

<Route path='/products' exact={true} component={() => <Async provider={() => import('.


/Products')} />} />

/Products/Products has been replaced with /Products , much better.

Head back to your browser and try to navigating to the different routes. You will notice how
there are bundles being loaded in every time one of our lazy routes are hit. That's it, you
know have lazy loaded routes and your mobile users will thank you.

94
Dealing with lazy loading/ code splitting

95
DataContext API

Leveraging the Context API in React.js

Follow me on Twitter, happy to take your suggestions on topics or improvements /Chris

The React Context exist so you don’t have to pass in data manually at every level.
Context is about sharing data to many components

In this article we will learn about the following topics:

The context API , what it is and why use it


Building blocks , we will learn about the different building blocks using a Context and
how they work together
In action , we will look at several examples of creating a Context and we will ensure we
learn about Dynamic contexts and how HOC, higher order components can help clean
up our Context code

If you ever get lost following the code samples in the article, have a look at this demo
containing all the code shown below:

https://github.com/softchris/react-context-demo

Why Context API and what is it?

96
DataContext API

The React Context exist so you don’t have to pass in data manually at every level. Context
is about sharing data to many components. The reason we need the Context API is that it’s
cumbersome to pass data from parent to child via props if there are many components
requiring the same data. By using the Context API we no longer pass this kind of shared
data with props.

When to use /not use it


Things that belong in a context is data that is considered global like a user or a cart etc. So
let’s try to list the different reasons for using a Context:

data needed in many places , data that needs to be used by many components like a
theme, user or a cart
pass props through many components , sometimes it’s better to use composition
over context when you want to pass a props value through many components

Building blocks and API


The Context API consists of some building blocks that it is important that we know about
what they are called but also what their role is:

context , the context object is an object holding the current context value and can be
subscribed to
provider , This is a React component that provides the value in question, it grabs it
from the context object
consumer , This is a React component that is able to consume the value provided by
the Provider and is able to show the value

This is all a bit theoretical and may sound a little confusing so let’s dive right into an example
to clear any confusion.

Context API in action


To utilize a Context in React we need to do the following:

create a context , we do this with a call to React.createContext(), this will return a


Context object that exposes a Provider Component as well as a Consumer Component
declare a provider , this is us grabbing the Provider Component reference available
in the context object we just created
declare a consumer , this is also a component that lives on the Context object and we
use this to show the value to the user

97
DataContext API

Creating a Context object


Let’s start by creating a React project using Create React App, CRA:

npx create-react-app context-demo


cd context-demo
npm start

Good, we have a project. Now let’s create a file called theme.js , it will hold our Context
object.

It’s quite straight-forward to create a Context object. For that we use the
React.createContext() method like so:

// theme.js

import React from 'react';

const ThemeContext = React.createContext('light');

export default ThemeContext;

Above we call createContext() and we give it an input parameter which is simply the
default value we want the context to have. We also export the object itself so we can use it
in other places.

That’s very little code to write to use something as powerful as a Context . We haven’t seen
anything yet though, so the fun has just begun:

Declare a Provider
Ok, so we have a Context object let’s grab a reference to a Provider next. For this, we will
first create a component file Sample.js , you can really call it anything you want but the point
is to have a React component to demonstrate how the Context object works. Let’s create a
component:

98
DataContext API

// Sample.js

import React from 'react';

import Theme from './theme';

const Sample = () => (

<Theme.Provider value='dark'>

// declare consumer

</Theme.Provider>

);

export default Sample;

Above we are declaring a normal functional React component and we also import our
Theme , our Context object. We then grab a reference to our provider by calling

Theme.Provider . At this point, nothing really works, because we are lacking a Consumer

component that can actually consume the value and thereby show it to a user.

Furthermore, we also set the value property to dark .

Wait wait, hold on… Didn’t we just set the value to light in our theme.js file, what’s the point
of doing that if we are going to override it in the Provider anyway? Very good question, let’s
save it a bit until we declared a Consumer and then it will all make sense.

Declare a Consumer
So next up is about declaring a Consumer component and show how we can show the value
to the user. Let’s add that to our code:

99
DataContext API

// Sample.js

import React from 'react';

import Theme from './theme';

const Sample = () => (


<Theme.Provider value='dark'>
<Theme.Consumer>
{theme => <div>Our theme is: {theme}</div>}
</Theme.Consumer>
</Theme.Provider>
);

export default Sample;

Above we added our Consumer , in the form of Theme.Consumer component and we can see
that we inside it define a function whose parameter is our theme value. We are then able to
show the theme value in a div.

Ok then, let’s get back to our question, why are we setting the value property in our
Theme.Provider component if we already set a default value in our theme.js file, here:

// theme.js

import React from 'react';

const ThemeContext = React.createContext('light');

export default ThemeContext;

Well, the default value above won’t be used if we declare a Provider . If we are missing a
Provider component, however, it will use the default value as a fallback. So the following

code will output dark as value, which is the value we give to the Provider :

const Sample = () => (


<Theme.Provider value='dark'>
<Theme.Consumer>
{theme => <div>Theme value: {theme}</div>}
</Theme.Consumer>
</Theme.Provider>
)

whereas this code will output light as value, e.g the default value:

100
DataContext API

// Sample.js with a Provider missing

const Sample = () => (


<Theme.Consumer>
{theme => <div>Theme value: {theme}</div>}
</Theme.Consumer>
);

Usage
Taking our Context for a spin means we need to create a Provider and a Consumer as we
did in the last section, however, most likely the Consumer part is baked into a Component
like so:

// ThemedButton.js
import Theme from 'theme.js';

const ThemedButton = (props) => (

<Theme.Consumer>

{theme => <button { ...props }>button with them: {theme}</button>}

</Theme.Consumer>

);
export default ThemedButton

This means that our code from the last section can be cleaned up somewhat to look like this:

// Sample.js

import React from 'react';

import Theme from './theme';


import ThemedButton from './ThemedButton';

const Sample = () => (

<Theme.Provider value='dark'>
<ThemedButton />
</Theme.Provider>
);

export default Sample;

101
DataContext API

As you can see the value from the Provider is being passed down through the props and
we can inside of the ThemedButton component access the theme property through the
Consumer .

Dynamic Context
What if we want to change the provider value? One way of doing that is by having a dynamic
context. We can achieve that by placing our Provider inside of a component and let its
value depend on the component state like so:

// AnyComponent.js
import React from 'react';

class AnyComponent extends React.Component {


state = {
theme: 'dark'
};

render() {
return (
<ThemeContext.Provider value={ this.state.theme }>
<ThemedButton />
</ThemeContext.Provider>
);
}
}

Now it’s easy for us to change the state and thereby we can change the value the Provider
is providing to any Consumer .

Changing the state example


Below we are creating a component containing a droplist with two different values light
and dark and when we switch between the values, the state is altered and because the
state is connected to the Provider , the provided value is changed with it.

Let’ look at the code:

102
DataContext API

// AnyComponent.js

import React from 'react';


import Theme from './theme';
import ThemedButton from './ThemedButton';

class AnyComponent extends React.Component {


state = {
theme: 'dark',
themes: ['light', 'dark']
};

handleSelect = (evt) => {


console.log('Changing value to ' + evt.target.value);

this.setState({
theme: evt.target.value
});
};

render() {
return (
<React.Fragment>
<h2>Any component</h2>
<select value = {this.state.theme}
onChange ={this.handleSelect}>
{ this.state.themes.map(t =>
<option value = {t} >{t}</option>)
}
</select>
<div>
Selected theme: {this.state.theme}
</div>
<Theme.Provider value ={this.state.theme}>
<ThemedButton theme={this.state.theme} />
</Theme.Provider>
</React.Fragment>
);

}
}

export default AnyComponent;

We can see from the above code that when the onChange event is triggered we invoke the
handleSelect() method and that leads to the state property theme being updated. That

same property theme is what the Theme.Provider is assigning as its value attribute.
Thereby a change in the droplist leads to the Provider component providing a new value. A
fairly simple code flow but it does show where we should change things to get the Consumer
component to display a new value.

103
DataContext API

Second example — a cart


Our next example is a little bit different. We have seen how we can expose a value from a
components state and make that the value of the Provider component and thereby we can
affect what the Provider provides. This can be taken to a further level. Further in the sense
that we can not only expose the value of a Provider to a Consumer but also methods,
methods that will allow us to change the provided value. Let’s look at some code for this:

// cart.js

import React from 'react';

const CartContext = React.createContext({


cart: void 0,
addItem: () => {}

});

export default CartContext;

We start with creating our Context object and this time we give it a more complex data type
than a string or a number. The input parameter to createContext() method is an object {}
with a property cart .

A note void 0 is just the same as undefined .

Next, we will create two different components:

CartPage, this will contain our Consumer component and thereby display the value
from our Context object
CartProvider, this will be a component that will not only provide the value from the
Context object but also expose a method with which we can change the provided

value

Let’s start with CartPage component:

104
DataContext API

// CartPage.js

import React from 'react';


import CartContext from './cart';

const products = [{
id: 1,
title: 'Fortnite'
}, {
id: 2,
title: 'Doom'
}, {
id: 3,
title: 'Quake'
}]

const CartPage = () => (


<CartContext.Consumer>
{({ cart, addItem }) => (
<React.Fragment>
<div>
<h2>Product list</h2>
{products.map(p => <button onClick={() => addItem(p)} value={p}>{p.title} . </butto
n>)}
</div>
<div>
<h2>Cart</h2>
{cart.map(item => <div> {item.title} </div>)}
</div>
</React.Fragment>
)}
</CartContext.Consumer>
);

export default CartPage;

We see above that we use CartContext component and that we define and display our cart
value, but there is an addition to it in the form of the addItem() method. This method will
allow us to change the cart item, but how you ask? Let’s have a look at our CartProvider
component next to find out the answer:

105
DataContext API

import React from 'react';


import CartPage from './CartPage';
import CartContext from './cart';

class CartProvider extends React.Component {


constructor() {
super();

this.state = {
cart: [],
addItem: (item) => {
this.setState({
cart: [...this.state.cart, { ...item }]
})
}
}
}

render() {
return (
<CartContext.Provider value = {this.state} >
<CartPage />
</CartContext.Provider>
);
}

export default CartProvider;

We can see here that the state object consists of the properties cart and addItem and
what gets passed into the value property of the CartContext.Provider is this.state e.g both
cart and addItem() . This means we could easily expand this with a removeItem()

function or whatever we need, this is how we get more than just a value exposed to a
Consumer component.

Higher order component


Sometimes a context needs to be provided in many places. In our example above imagine
the cart being used inside of a header that wants to show how many items you have in a
cart. There might also be dedicated Cart Page where you can see the cart content more in
detail. It might get tedious to have to wrap all those component content in a Consumer tag.
For those situations, it’s better to use a HOC, a higher order component. This means we can
create a function where we use our component as input and we augment the context data.

It can look like the following:

106
DataContext API

// withCart.js
import CartContext from './cart';
import React from 'react';

export const withCart = (Component) => {


return function fn(props) {
return (
<CartContext.Consumer>
{(context) => <Component {...props} {...context} />}
</CartContext.Consumer>
);
};
};

As you can see above, we are using a Consumer to make this happen but we also use the
spread parameter { ...context} to transfer what is in the context object to the underlying
component. Now we can easily use this function to decorate our component, like so:

// Header.js
import React from 'react';
import withCart from './withCart';

class Header extends React.Component {


render() {
const { cart } = this.props;

return (
{cart.length === ?
<div>Empty cart</div> :
<div>Items in cart: ({cart.length})</div>
}
);
}

const HeaderWithCart = withCart(Header);


export default HeaderWithCart;

Summary
In this article, we have covered quite a lot. We have explained what the Context API is and
when to use it. We also talked about its building blocks Provider and Consumer .
Furthermore, we have covered how to update provided values and lastly how we can clean
up a bit using a HOC, a higher order component. Hopefully, you have found this useful. :)

Follow me on Twitter, happy to take your suggestions on topics or improvements /Chris

107
DataContext API

108
Decorators

109
Render props

Using Render props in React - lifecycle


begone!
Moved to my blog

110
Hooks

React Hooks - best thing since sliced


bread?
Hooks are an upcoming feature that lets you use state and other React features without
writing a class component - functions FTW.

Hooks is the latest pattern and an experimental feature that's supposedly better than sliced
bread. Everyone used to go nuts over Render props but now it's all hooks.

Hooks are currently in React v16.8.0-alpha.0 so you can try them out already :)

Problems Hooks are trying to address


Every time something new comes out we get excited. It's ketchup, it's the best thing since
sliced bread and so on. We hope that this will finally be the solution to all our problems, so
we use it, again and again and again. We've all been guilty of doing this at one time of
another, abusing a pattern or paradigm and yes there has always been some truth to it that
the used pattern has been limited.

Below I will try to lay out all the different pain points that makes us see Hooks as this new
great thing. A word of caution though, even Hooks will have drawbacks, so use it where it
makes sense. But now back to some bashing and raving how the way we used to build

111
Hooks

React apps were horrible;)

There are many problems Hooks are trying to address and solve. Here is a list of offenders:

wrapper hell, we all know the so called wrapper hell. Components are surrounded by
layers of providers , consumers , higher-order components , render props , and other
abstractions, exhausted yet? ;)

Like the whole wrapping itself wasn't bad enough we need to restructure our components
which is tedious, but most of all we loose track over how the data flows.

increasing complexity, something that starts out small becomes large and complex
over time, especially as we add lifecycle methods
life cycle methods does too many things, components might perform some data
fetching in componentDidMount and componentDidUpdate . Same componentDidMount
method might also contain some unrelated logic that sets up event listeners, with
cleanup performed in componentWillUnmount

Just create smaller components?

In many cases it’s not possible because:

difficult to test, stateful logic is all over the place, thus making it difficult to test
classes confuse both people and machines, you have to understand how this
works in JavaScript, you have to bind them to event handlers etc. The distinction
between function and class components in React and when to use each one leads to
disagreements and well all know how we can be when we fight for our opinion, spaces
vs tabs anyone :)?.
minify issues, classes present issues for today’s tools, too. For example, classes don’t
minify very well, and they make hot reloading flaky and unreliable. Some of you might
love classes and some of you might think that functions is the only way. Regardless of
which we can only use certain features in React with classes and if it causes these
minify issues we must find a better way.

Selling point of Hooks


Hooks let you use more of React’s features without classes. Not only that, we are able to
create Hooks that will allow you to:

extract stateful logic from a component, so it can be tested independently and


reused.
reuse stateful logic, without changing your component hierarchy. This makes it easy to
share Hooks among many components or with the community.

112
Hooks

What is a hook?
Hooks let you split one component into smaller functions based on what pieces are
related (such as setting up a subscription or fetching data), rather than forcing a split based

on lifecycle methods.

Let's have an overview of the different Hooks available to use. Hooks are divided into Basic
Hooks and Additional Hooks . Let's list the Basic Hooks first and mention briefly what their

role is:

Basic Hooks
useState, this is a hook that allows you to use state inside of function component
useEffect, this is a hook that allows you to perform side effect in such a way that it
replaces several life cycle methods
useContext, accepts a context object (the value returned from React.createContext)
and returns the current context value, as given by the nearest context provider for the
given context. When the provider updates, this Hook will trigger a rerender with the
latest context value.

We will focus on useState and useEffect in this article.

Additional Hooks
We will not be covering Additional Hooks at all as this article would be way too long but you
are encouraged to read more about them on Additional Hooks

useReducer, alternative to useState , it accepts a reducer and returns a pair with the
current state and a dispatch function
useCallback, will return a memoized version of the callback that only changes if one of
the inputs has changed. This is useful when passing callbacks to optimized child
components that rely on reference equality to prevent unnecessary renders
useMemo, passes a create function and an array of inputs. useMemo will only
recompute the memoized value when one of the inputs has changed. This optimization
helps to avoid expensive calculations on every render.
useRef, returns a mutable ref object whose .current property is initialized to the
passed argument (initialValue). The returned object will persist for the full lifetime of the
component
useImperativeHandle, customizes the instance value that is exposed to parent
components when using ref
useLayoutEffect, the signature is identical to useEffect, but it fires synchronously after

113
Hooks

all DOM mutations. Use this to read layout from the DOM and synchronously re-render
useDebugValue, can be used to display a label for custom hooks in React DevTools

As you can see above I've pretty much borrowed the explanation for each of these
Additional Hooks from the documentation. The aim was merely to describe what exist, give

a one liner on each of them and urge you to explore the documentation once you feel you've
mastered the Basic Hooks .

First example - useState


This hook let's us use state inside of a function component. Yep I got your attention now
right? Usually that's not possible and we need to use a class for that. Not anymore. Let's
show what using useState hook looks like. We need to do two things to get started with
hooks:

scaffold a project using Create React App


upgrade react and react-dom

The first one we will solve by typing:

npx create-react-app hooks-demo

next we need to upgrade react and react-dom so they are using the experimental version
of React where hooks are included:

yarn add react@next react-dom@next

Now we are good to go:

import React, { useState } from 'react';

const Counter = () => {


const [counter, setCounter] = useState(0);
return (
<div>
{counter}
<button onClick={() => setCounter(counter + 1)} >Increment</button>
</div>
)
}

export default Counter;

Ok we see that we use the Hook useState by invoking it and we invoke it like so:

useState(0)

114
Hooks

This means we give it an initial value of 0. What happens next is that we get an array back
that we do a destructuring on. Let's examine that closer:

const [counter, setCounter] = useState(0);

Ok, we name the first value in the array counter and the second value setCounter . The
first value is the actual value that we can showcase in our render method. The second
value setCounter() is a function that we can invoke and thereby change the value of
counter . So in a sense, setCounter(3) is equivalent to writing:

this.setState({ counter: 3 })

Just to ensure we understand how to use it fully let's create a few more states:

import React, { useState } from 'react';

const ProductList = () => {


const [products] = useState([{ id: 1, name: 'Fortnite' }]);
const [cart, setCart] = useState([]);

const addToCart = (p) => {


const newCartItem = { ...p };
setCart([...cart, newCartItem]);
}
return (
<div>
<h2>Cart items</h2>
{cart.map(item => <div>{item.name}</div>)}
<h2>Products</h2>
{products.map(p => <div onClick={() => addToCart(p)}>{p.name}</div>)}
</div>
)
}
export default ProductList;

Above we are creating the states products and cart and in doing so we also get their
respective change funciton setProducts and setCart . We can see in the markup we
invoke the method addToCart() if clicking on any of the items in our products list. This
leads to the invocation of setCart , which leads to the selected product ot be added as a
cart item in cart . This is a simple example but it really showcases the usage of setState
hook.

Handling side-effects with a Hook

115
Hooks

The Effect hook is meant to be used to perform side effects like for example HTTP calls. It
performs the same task as life cycle methods componentDidMount , componentDidUpdate , and
componentWillUnmount .

Here is how we can use it:

116
Hooks

import React, { useEffect, useState } from 'react';

const products = [{ id: 1, name: "Fortnite" }, { id: 2, name: "Doom" }];

const api = {
getProducts: () => {
return Promise.resolve(products);
},
getProduct: (id) => {
return Promise.resolve(products.find(p => p.id === id));
}
}

const ProductList = () => {


const [products, setProducts] = useState([]);
const [product, setProduct] = useState('');
const [selected, setSelected] = useState(2);

async function fetchData() {


const products = await api.getProducts();
setProducts(products);
}

async function fetchProduct(productId) {


const p = await api.getProduct(productId);
setProduct(p.name);
}

useEffect(() => {
console.log('use effect');
fetchData();
fetchProduct(selected);
}, [selected]);

return (
<React.Fragment>
<h1>Async shop</h1>
<h2>Products</h2>
{products.map(p => <div>{p.name}</div>)}
<h3>Selected product</h3>
{product}
<button onClick={() => setSelected(1)}>Change selected</button>
</React.Fragment>
);

export default ProductList;

Ok, a lot of interesting things was happening here. Let's start by looking at our usage of
useEffect :

117
Hooks

useEffect(() => {
console.log('use effect');
fetchData();
fetchProduct(selected);
}, [selected]);

What we are seeing above is us calling fetchData and fetchProduct . Both these methods
calls methods marked by async . Why can't we just make the calling function in useEffect
async, well that's a limitation of hooks unfortunately.

Looking at the definition of these two methods it looks like the following:

async function fetchData() {


const products = await api.getProducts();
setProducts(products);
}

async function fetchProduct(productId) {


const p = await api.getProduct(productId);
setProduct(p.name);
}

We see above that we are calling getProducts and getProduct on api which both returns
a Promise. After having received the resolved Promise, using await we call setProducts
and setProduct that are functions we get from our useState hook. Ok, so this explains
how useEffect in this case acts like componentDidMount but there is one more detail. Let's
look at our useEffect function again:

useEffect(() => {
console.log('use effect');
fetchData();
fetchProduct(selected);
}, [selected]);

The interesting part above is the second argument [selected] . This is us looking at the
selected variable and let ourselves be notified of changes, if a change happens to

selected then we will run our useEffect function.

Now, try hitting the bottom button and you will see setSelected being invoked which trigger
useEffect because we are watching it.

Life cycle

118
Hooks

Hooks replaces the needs for many life cycle methods in general so it's important for us to
understand which ones.

Let's discuss Effect Hooks in particular and their life cycle though.

The following is known about it's life cycle:

By default, React runs the effects after every render


Our effect is being run after React has flushed changes to the DOM — including the first
render

Accessing the DOM tree


Let's talk about when we access the DOM tree, to perform a side effect. If we are not using
Hooks we would be doing so in the methods componentDidMount and componentDidUpdate .
The reason is we cant use the render method cause then it would happen to early.

Let's show how we would use life cycle methods to update the DOM:

componentDidMount() {
document.title = 'Component started';
}

componentDidUpdate() {
document.title = 'Component updated'
}

We see that we can do so using two different life cycle methods.

Accessing the DOM tree with an Effects Hook would look like the following:

const TitleHook = () => {


const [title, setTitle] = useState('no title');

useEffect(() => {
document.title = `App name ${title} times`;
})
}

As you can see above we have access to props as well as state and the DOM.

Let's remind ourselves what we know about our Effect Hook namely this:

Our effect is being run after React has flushed changes to the DOM — including the
first render

That means that two life cycle methods can be replaced by one effect.

119
Hooks

Handling set up/ tear down


Let's now look at another aspect of the useEffect hook namely that we can, and we should,
clean up after ourselves. The idea for that is the following:

useEffect(() => {
// set up
// perform side effect
return () => {
// perform clean up here
}
});

Above we see that inside of our useEffect() function we perform our side effect as usual,
but we can also set things up. We also see that we return a function. Said function will be
invoked the last thing that happens.

What we have here is set up and tear down. So how can we use this to our advantage?
Let's look at a bit of a contrived example so we get the idea:

useEffect(() => {
const id = setInterval(() => console.log('logging'));

return () => {
clearInterval(id);
}
})

The above demonstrates the whole set up and tear down scenario but as I said it is a bit
contrived. You are more likely to do something else like setting up a socket connection for
example, e.g some kind of subscription, like the below:

onMessage = (message) => {


// do something with message
}

useEffect(() => {
chatRoom.subscribe('roomId', onMessage)

return () => {
chatRoom.unsubscribe('roomId');
}
})

Can I create my own Hook?

120
Hooks

Yes you can. With useState and useEffect the world is completely open. You can create
whatever hook you need.

Ask yourself the following questions; Will my component have a state? Will I need to do a
DOM manipulation or maybe an AJAX call? Most of all, is it something usable that more than
one component can benefit from? If there are several yes here you can use a hook to create
it.

Let's look at some interesting candidates and see how we can use hooks to build them out:

You could be creating things like:

a modal, this has a state that says wether it shows or not and we will need to
manipulate the DOM to add the modal itself and it will also need to clean up after itself
when the modal closes

a feature flag, feature flag will have a state where it says wether something should be
shown or not, it will need to get its state initially from somewhere like localStorage
and/or over HTTP

a cart, a cart in an e-commerce app is something that most likely follows us everywhere
in our app. We can sync a cart to localStorage as well as a backend endpoint.

Feature flag
Let's try to sketch up our hook and how it should be behaving:

import React, { useState } from 'react';

function useFeatureFlag(flag) {
let flags = localStorage.getItem("flags");
flags = flags ? JSON.parse(flags) : null;

const [enabled] = useState(Boolean(flags ? flags[flag]: false));

return [enabled];
}

export default useFeatureFlag;

Above we have created a hook called useFeatureFlag . This reads its value from
localStorage and it uses useState to set up our hook state. The reason for us not

destructuring out a set method in the hook is that we don't want to change this value unless
we reread the whole page, at which point we will read from localStorage anew.

Now we have create our custom Hook, let's take it for a spin:

121
Hooks

import React from 'react';


import useFeatureFlag from './flag';

const TestComponent = ({ flag }) => {


const [enabled] = useFeatureFlag(flag);
debugger;
return (
<React.Fragment>
<div>Normal component</div>
{enabled &&
<div>Experimental</div>
}

</React.Fragment>
);
};

export default TestComponent;

// using it
<TestComponent flag="experiment1">

We said earlier we weren't interested in changing the value exposed by useFeatureFlag . To


control our feature flags we opt for creating a specific Admin page. We count on the Admin
page to be on a specific page and the component with the feature flag on another page.
Result of that is were we to navigate between the two pages then we can guarantee that the
feature flag component reads from localStorage .

Imagine you have an admin page. On that admin page it would be neat if we could list all the
flags and toggle them any way we want to. Let's write such a component:

122
Hooks

import React, { useState } from 'react';

const useFlags = () => {


let flags = localStorage.getItem("flags");
flags = flags ? JSON.parse(flags) : {};

const [ flagsValue, setFlagsValue ] = useState(flags);

const updateFlags = (f) => {


localStorage.setItem("flags", JSON.stringify(f));
setFlagsValue(f);
}

return [flagsValue, updateFlags];


}

const FlagsPage = () => {


const [flags, setFlags] = useFlags();

const toggleFlag = (f) => {


const currentValue = Boolean(flags[f]);
flags[f] = !currentValue;
setFlags(flags)
}
return (
<React.Fragment>
<h1>Flags page</h1>
{Object.keys(flags).filter(key => flags[key]).map(flag => <div><button onClick={
() => toggleFlag(flag)}>{flag}</button></div>)}
</React.Fragment>
)
}

export default FlagsPage;

What we are doing above is to read out the flags from localStorage and then we render
them all out. While rendering them out, flag by flag, we also hook-up ( I know we are talking
about hooks here but no pun intended, really :) ) a method on the onClick . That method is
toggleFlag that let's us change a specific flag. Inside of toggleFlag we not only set the

new flag value but we also ensure our flags have the latest updated value.

It should also be said that us creating useFlags hook have made the code in FlagsPage
quite simple, so hooks are good at cleaning up a bit too.

Summary

123
Hooks

In this article we have tried to explain the background and the reason hooks where created
and what problems it was looking to address and hopefully fix.

We have learned the following, hopefully;):

useState, is a Hook we can use to persist state in a functional component


useEffect is also a Hook but for side effects

we can use one or both of the mentioned hook types and create really cool and reusable
functionality, so go out there, be awesome and create your own hooks.

Further reading
Hooks documentation
Motivation behind hooks

124
Jest

Jest
In this article we will cover the testing framework Jest. We will learn how to:

write tests, it's a breeze to write tests and assert on specific conditions
manage our test suite, by running specific tests as well as specific test files by utilising
the pattern matching functionality
debug our tests, by augmenting VS Code we can gain the ability to set break points in
our tests and create a real nice debugging experience
snapshot mastery, learn how using snapshots can give you increased confidence that
your components are still working after a change you made
leverage mocking, mocking dependencies can ensure you only test what you want to
test and Jest has great defaults when it comes to mocking
coverage reports, we have come to expect a good coverage tool to be included in all
good testing libraries. Jest is no different and it's really easy to run coverage reports and
quickly find what parts of your code that could benefit from some more testing

Jest sells itself by saying it's

Delightful JavaScript testing

125
Jest

What makes is delightful? It boosts that it has a zero-configuration experience. Ok, we are
getting closer to the answer.

Great performance by tests running in parallell thanks to workers.


Built in coverage tool
Works with typescript thanks to ts-jest

Get started
Let's try to set it up and see how much configuration is needed. If you just want to try it,
there is a Jest REPL where you will be able to write tests among other things.

Writing our first test


To make the test runner find our tests we need to follow one of three conventions:

Create a __tests__\ directory and place your files in there


Make file match *spec.js
Make file match .test.js

Ok, so now we know how Jest will find our files, how about writing a test?

// add.js
function add(a, b) {
return a + b;
}

module.exports = add;

// __tests__/add.js

const add = require('../add');


describe('add', () => {
it('should add two numbers', () => {
expect(add(1, 2)).toBe(3);
});
});

We see above that we are using describe to create a test suite and it to create a test
within the test suite. We also see that we use expect to assert on the result. The expect
gives us access to a lot of matchers, a matcher is the function we call after the expect :

expect(something).matcher(value)

126
Jest

As you can see in our test example we are using a matcher called toBe() which essentially
matches what's inside the expect to what's inside the matcher, example:

expect(1).toBe(1) // succeeds
expect(2).toBe(1) // fails

There are a ton of matchers so I urge you to have a look at the ones that exists and try to
use the appropriate matcher Matchers

Running our test


The simplest thing we can do is just to create a project using create-react-app , cause Jest
is already set up in there. Once we have the project created and all dependencies installed
we can simply run:

yarn test

It will show the above image containing:

One executed test suite,


one passing tests and host of commands that we will explore in a bit. It seems to have
run the file src/App.test.js . Let's have a look at said file:

127
Jest

// src/App.test.js

import React from 'react';


import ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {


const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});

As we can see it has created a test using it and have also created a component using
ReactDOM.render(<App />, div) , followed by cleaning up after itself by calling

ReactDOM.unmount(div) . We haven't really done any assertions at this point, we have just

tried to create a component with no errors as the result, which is good to know though.

How bout we try adding add.js file and its corresponding test?

Let's first add add.js , like so:

// add.js

function add(a,b) {
return a + b;
}

export default add;

followed by the test

// __tests__/add.js

import add from '../add';

it('testing add', () => {


const actual = add(1,3);
expect(actual).toBe(4);
});

128
Jest

Our Jest session is still running in the terminal:

We can see that we now have two passing tests.

Debugging
Any decent test runner/framework should give us the ability to debug our tests. It should give
us the ability to:

run specific tests


ignore tests
let us add breakpoints in our IDE (more up to the IDE vendor to make that happen)
let us run our tests in a Browser

Run specific test files


Let us look at how to do these things, let's start with running specific tests. First off we will
add another file subtract.js and a corresponding test.

// subtract.js

function subtract(a,b) {
return a - b;
}

export default subtract;

and the test:

129
Jest

// __tests__/subtract.js
import subtract from '../subtract';

it('testing subtract', () => {


const actual = subtract(3,2);
expect(actual).toBe(1);
});

Let's have a look at our terminal again and especially at the bottom of it:

If you don't see this press w as indicated on the screen. The above give us a range of
commands which will make our debugging easier:

a , runs all the tests

p this will allow us to specify a pattern, typically we want to specify the name of a file

here to make it only run that file.


t it does the same as p but it let's us specify a test name instead

q , quits the watch mode

Enter , to trigger a test run

Given the above description we will try to filter it down to only test the add.js file so we type
p :

130
Jest

This takes us to a pattern dialog where we can type in the file name. Which we do:

Above we can now see that only the add.js file will be targeted.

Run specific tests


We have learned how to narrow it down to specific files. We can narrow it down to specific
tests even using the p , pattern approach. First off we will need to add a test so we can
actually filter it down:

// __tests__/add.js

import add from '../add';

it('testing add', () => {


const actual = add(1,3);
expect(actual).toBe(4);
});

it('testing add - should be negative', () => {


const actual = add(-2,1);
expect(actual).toBe(-1);
});

131
Jest

At this point our terminal looks like this:

So we have two passing tests in the same file but we only want to run a specific test. We do
that by adding the .only call to the test, like so:

it.only('testing add', () => {


const actual = add(1,3);
expect(actual).toBe(4);
});

132
Jest

and the terminal now looks like so:

We can see that adding .only works really fine if we only want to run that test. We can use
.skip to make the test runner skip a specific test:

it.skip('testing add', () => {


const actual = add(1,3);
expect(actual).toBe(4);
});

133
Jest

The resulting terminal clearly indicated that we skipped a test:

Debugging with Break points


Now this one is a bit IDE dependant, for this section we will cover how to do this in VS Code.
First thing we are going to do is install an extension. Head over to the extension menu and
search for Jest . The following should be showing:

134
Jest

Install this extension and head back to your code. Now we have some added capabilities. All
of our tests should have a Debug link over every single test. At this point we can add a
breakpoint and then press our Debug link. Your break point should now be hit and it should
look like so:

Snapshot testing
Snapshot is about creating a snapshot, a view of what the DOM looks like when you render
your component. It's used to ensure that when you or someone else does a change to the
component the snapshot is there to tell you, you did a change, does the change look ok?

If you agree with the change you made you can easily update the snapshot with what DOM
it now renders. So snapshot is your friend to safeguard you from unintentional changes.

Let's see how we can create a a snapshot. First off we might need to install a dependency:

yarn add react-test-renderer --save

Next step is to write a component and a test to go along with it. It should look something like
this:

// Our component
import React from 'react';

const Todos = ({ todos }) => (


<React.Fragment>
{todos.map(todo => <div>{todo}</div>)}
</React.Fragment>
);

export default Todos;

135
Jest

// The test

import renderer from 'react-test-renderer';


import React from 'react';

import Todos from '../Todos';

test('Todo - should create snapshot', () => {


const component = renderer.create(
<Todos todos={['item1', 'item2']} />,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
})

Note how import , imports the component we are about to test:

import Todos from '../Todos';

This is followed by using the renderer to create an instance of our component. Next step is
turn that component into a JSON representation like so component.toJSON() and lastly we
assert on this by calling expect(tree).toMatchSnapshot() , this will call a snapshot that will
place itself in a __snapshots__ directory under your tests directory.

Managing the snapshot


Ok, so we have a snapshot, now what? Let's do a change to our todo component, like so:

import React from 'react';

const Todos = ({ todos }) => (


<React.Fragment>
{todos.map(todo => (
<React.Fragment>
<h3>{todo.title}</h3>
<div>{todo.description}</div>
</React.Fragment>
))}
</React.Fragment>
);

export default Todos;

136
Jest

We see that our todo is an object instead of a string so it has a title and description
property. This WILL make our snapshot react and it will say the following:

It clearly indicates something is different and asks us to inspect the code. If we are happy
with the changes we should press u to update the snapshot to its new version. So look at
the code and yes this is an intended change so therefore we press u . We end up with the
following image telling us everything is ok:

Mocking
Mocking is one of those things that needs to work well. Mocking in Jest is quite easy. You
need to create your mocks in a directory that is adjacent to your module, or more like a child
directory to the module. Let's show what I mean in code. Imagine you have the following
module:

137
Jest

// repository.js

const data = [{
title: 'data from database'
}];

export default data;

Let's look at a test for this one:

// __tests__/repository.js

import data from '../repository';

describe('testing repository data', () => {


it('should return 1 item', () => {
console.log(data);
expect(data.length).toBe(1);
});
});

Not the best of tests but it is "a test". Let's create our mock so that our file structure look like
so:

repository.js
__mocks__/repository.js

Our mock should look like this:

// __mocks__/repository.js
const data = [{
title: 'mocked data'
}];

export default data;

To use this mock we need to call jest.mock() inside of our test, like so:

138
Jest

// __tests__/repository.js

import data from '../repository';


jest.mock('../repository');

describe('testing repository data', () => {


it('should return 1 item', () => {
console.log(data);
expect(data.length).toBe(1);
});
});

Now it uses our mock instead of the actual module. Ok you say, why would I want to mock
the very thing I want to test. Short answer is - you wouldn't. So therefore we are going to
create another file consumer.js that use our repository.js . So let's look at the code for
that and its corresponding test:

// consumer.js

import data from './repository';


const item = { title: 'consumer' };

export default [ ...data, { ...item}];

Above we clearly see how our consumer use our repository.js and now we want to mock
it so we can focus on testing the consumer module. Let's have a look at the test:

import data from '../consumer';


jest.mock('../repository');

describe('testing consumer data', () => {


it('should return 2 items', () => {
console.log(data);
expect(data.length).toBe(2);
});
});

We use jest.mock and mocks away the only external dependency this module had.

What about libs like lodash or jquery , things that are not modules that we created but is
dependant on? We can create mocks for those at the highest level by creating a __mocks__
directory.

There is a lot more that can be said about mocking, for more details check out the
documentation Mocking docs

139
Jest

Coverage
We have come to the final section in this chapter. This is about realizing how much of our
code is covered by tests. To check this we just run:

yarn test --coverage

This will give us a table inside of the terminal that will tell us about the coverage in
percentage per file. It will also produce a coverage directory that we can navigate into and
find a HTML report of our coverage. But first off let's change the add.js file to add a piece
of logic that needs a test, like so:

function add(a,b) {
if(a > 0 && b > 0 ) {
return a + b;
}
throw new Error('parameters must be larger than zero');
}

export default add;

Now we can see we have more than one path through the application. If our input params
are larger than zero then we have existing tests that cover it. However if one or more
parameters is below zero then we enter a new execution path and that one is NOT covered
by tests. Let's see what that looks like in the coverage report by navigating to
coverage/lcov-report . We can show this by typing for example http-server -p 5000 and

we will get a report looking like this:

Now we can navigate to src/add.js and it should look like this:

140
Jest

Now we can clearly see how our added code is indicated in red and that we need to add a
test to cover that new execution path.

Next we add a test to cover for this, like so:

import add from '../add';

describe('add', () => {
it('testing addition', () => {
const actual = add(1,2);
expect(actual).toBe(3);
})

it('testing addition with neg number', () => {


expect(() => {
add(-1,2);
}).toThrow('parameters must be larger than zero');
})
})

Our second case should now cover for the execution path that leads to an exception being
thrown. Let's rerun our coverage report:

141
Jest

Summary
We've looked at how to write tests. We've also looked at how to debug our tests using an
extension from VS Code which have allowed us to set breakpoints.

Furthermore we've learned what snapshots are and how to best use them to our advantage.

Next up we've been looking at leveraging mocking to ensure we are in complete isolation
when we test.

Lastly we've looked at how we can generate coverage reports and how that can help you to
track down parts of your code that could really benefit from some more testing.

Further reading
The official docs for Jest can be found here Official docs

142
Nock

Mocking HTTP calls with Nock


Nock is used to mock calls to HTTP. It makes it possible for us to specify what URLs to listen
to and what to respond with. This is a fairly short article that shows how you use the library
nock .

In this article we will cover:

set up, setting up a nock and specify a mock response


query parameters, see how we can set up our nock with query parameters
verification, we should always verify that our nocks where hit. If they weren't then
something changed and we need to change our tests to reflect that

Scenario
Imagine we have the following files:

products.js, a service that can retrieve data for us


ProductsList.js, a component that calls a method on products.js to get data and render
that

Let's have a look at what these two modules look like:

// products.js

export const getProducts = async () => {


const response = await fetch('http://myapi.com/products');
const json = await response.json();

return json.products;
}

Above we can see that we do a fetch() call to url http://myapi.com/products and


thereafter we transform the response snd dig out the data products . Let's have a look at
the component:

143
Nock

// ProductsList.js

import React from 'react';


import { getProducts } from '../products';

const Products = ({ products }) => (


<React.Fragment>
{products.map(p => <div>{product.name}</div>)}
</React.Fragment>
);

class ProductsContainer extends React.Component {


state = {
products: [],
}

async componentDidMount() {
const products = await getProducts();
this.setState({
products
});
}

render() {
return (
<Products products={this.state.products} />
);
}
}

export default ProductsContainer;

We can see that we use product.js module and call getProducts() in the
componentDidMount() and end up rendering the data when it arrives.

Testing it
If we wanted to test ProductsList.js module we would want to focus on mocking away
products.js cause it is a dependency. We could use the library nock for this. Let's start off

by installing nock , like so:

yarn add nock

Let's now create a test __tests__/ProductsList.js and define it like the following:

144
Nock

// __tests__/ProductsList.js

import React from 'react';


import ReactDOM from 'react-dom';
import ProductsList from '../ProductsList';
import nock from 'nock';

it('renders without crashing', () => {


const div = document.createElement('div');
ReactDOM.render(<ProductsList />, div);
ReactDOM.unmountComponentAtNode(div);
});

Let's see first what happens if we don't set up a nock :

We end up with the following:

As you can see from the above it attempts to perform a network request. We should never
do that when running a test. We could add a Jest mock for this that is definitely one way to
solve it, then it would look like this:

// __mocks__/products.js
export const getProducts = async () => {
const products = await Promise.resolve([{ name: 'test' }]);
return products;
}

That works but let's look at how to solve it with nock . Because we are attempting to call
fetch() in a node environment we need to ensure it is set up correctly. Suggestion is to set

up the global.fetch and assign node-fetch to it, like so:

145
Nock

// setupTests.js

global.fetch = require('node-fetch');

Let's now add nock to our test, like so:

import React from 'react';


import ReactDOM from 'react-dom';
import ProductsList from '../ProductsList';
import nock from 'nock';

it('renders without crashing', () => {


const scope = nock('http://myapi.com')
.get('/products')
.reply(200, {
products: [{ id: 1, name: 'nocked data' }]
}, {
'Access-Control-Allow-Origin': '*',
'Content-type': 'application/json'
});

const div = document.createElement('div');


ReactDOM.render(<ProductsList />, div);
ReactDOM.unmountComponentAtNode(div);
});

Note above how we invoke the nock() method by first giving it the baseUrl
http://myapi.com followed by the path /products and the HTTP verb get and how we

define what the response should look like with reply() . We also give the reply() method
a second argument to ensure CORS plays nicely. At this point our test works.:

146
Nock

Query parameters
What if we have a url that looks like this:

http://myapi.com/products?page=1&pageSize=10;

How we do we set up our nock to match it? Well, we can use the helper method query for
that, like so:

nock('http://myapi.com')
.get('/products')
.query({ page: 1, pageSize: 10 })

Verify your mock/s


It's considered best practice to verify that the mocks you have set up are being hit. To do
that we can call done() on the returned reference when we are calling nock like so:

const scope = nock('http://myapi.com')


.get('/products')
.reply(200, {
products: [{ id: 1, name: 'nocked data' }]
}, {
'Access-Control-Allow-Origin': '*',
'Content-type': 'application/json'
});

scope.done();

So what happens when we set up a mock and it's not being it? Well let's add another call to
our test, like so:

const users = nock('http://myapi.com')


.get('/users')
.reply(200, {
products: [{ id: 1, name: 'user' }]
}, {
'Access-Control-Allow-Origin': '*',
'Content-type': 'application/json'
});

Now it looks like this:

147
Nock

Block HTTP calls


You should never let a HTTP call happen for real so therefore make sure to shut off that
ability. We can do so by adding the following line to setupTests.js :

// setupTests.js

import nock from 'nock';


nock.disableNetConnect();

Summary
We have briefly explained what nock is and how to use it for different cases. This is just
one way of many to handle HTTP calls.

There are a lot more you can do with nock , we have barely scraped the surface. Have a
look at the official documentation Nock documentation

148
Enzyme

149
react-testing-library

Testing the component surface with React


testing library
React Testing Library is a different testing library in that it tests the surface of your

component rather than the internals. You can change your components as much as you
want as long as they render the data the same way or React in the same way if you fill in
data or press a button for example.

This is what the author the library Kent Dodds says about it:

Simple and complete React DOM testing utilities that encourage good testing practices

It's a lightweight solution for testing React components. It provides utility functions on top of
react-dom and react-dom/utils . Your tests work on DOM nodes over React component

instances.

In this article we will cover the following:

writing a test, show how simple it is to write a test, instantiate a component and assert
on it
dealing with events, we will learn how we can trigger event and assert on the resulting

150
react-testing-library

component afterwards
asynchronous actions, we will learn how we can trigger and wait for asynchronous
actions to finish
manage input, we will learn how to send key strokes to input elements on our
components and assert on the result

It's easy to get started with, you just need to install react-testing-library :

yarn add react-testing-library

Writing a test
Let's look at a real scenario and see what we mean. We will create:

Todos.js a component that allows you to render a list of Todos and it also allows you to
select a specific Todo item
Todos.test.js, our test file

Our component code looks like this:

151
react-testing-library

// Todos.js

import React from 'react';


import './Todos.css';

const Todos = ({ todos, select, selected }) => (


<React.Fragment>
{todos.map(todo => (
<React.Fragment key={todo.title}>
<h3 data-testid="item" className={ selected && selected.title === todo.title ?
'selected' :'' }>{todo.title}</h3>
<div>{todo.description}</div>
<button onClick={() => select(todo)}>Select</button>
</React.Fragment>
))}
</React.Fragment>
);

class TodosContainer extends React.Component {


state = {
todo: void 0,
}

select = (todo) => {


this.setState({
todo,
})
}

render() {
return (
<Todos { ...this.props } select={this.select} selected={this.state.todo} />
);
}
}

export default TodosContainer;

Now to the test:

152
react-testing-library

// Todos.test.js

import {render, Simulate, wait} from 'react-testing-library';


import React from 'react';
import 'jest-dom/extend-expect'
import Todos from '../Todos';

const todos = [{
title: 'todo1'
},
{
title: 'todo2'
}];

describe('Todos', () => {
it('finds title', () => {
const {getByText, getByTestId, container} = render(<Todos todos={todos} />);
})

});

We can see from the above code that we are using some helpers from react-testing-
library :

render , this will render our component

Simulate , this will help us trigger things like a click event or change the input data

for example
wait , this allows us to wait for an element to appear

Looking at the test itself we see that when we call render we get an object back that we do
destructuring on:

const {getByText, getByTestId, container} = render(<Todos todos={todos} />)

and we end up with the following helpers:

getByText , this grabs an element by it's text content

getByTestId , this grabs an element by data-testid , so if you have an attribute on

your element like so data-testid="saved you would be querying it like so


getByTestId('saved')

container , the div your component was rendered to

Let's fill in that test:

153
react-testing-library

// Todos.test.js

import {render, Simulate, wait} from 'react-testing-library'


import React from 'react';
import 'jest-dom/extend-expect'
import Todos from '../Todos';

const todos = [{
title: 'todo1'
},
{
title: 'todo2'
}];

describe('Todos', () => {
it('finds title', () => {
const {getByText, getByTestId, container} = render(<Todos todos={todos} />);
const elem = getByTestId('item');
expect(elem.innerHTML).toBe('todo1');
})
});

As we can see above we are able to render our element and is also able query for an h3
element by using the container and the querySelector . Finally we assert on it.

Handling actions
Let's have a look at our component again. Or rather let's look at an excerpt of it:

// excerpt of Todos.js

const Todos = ({ todos, select, selected }) => (


<React.Fragment>
{todos.map(todo => (
<React.Fragment key={todo.title}>
<h3 className={ selected && selected.title === todo.title ? 'selected' :'' }>{
todo.title}</h3>
<div>{todo.description}</div>
<button onClick={() => select(todo)}>Select</button>
</React.Fragment>
))}
</React.Fragment>
);

We see above that we try to set the CSS class selected if a todo is selected. The way to
get a Todo selected is to click on it, we can see how we invoke the select method when
we click on the button that is rendered, one per item. Let's try to test this out by adding a

154
react-testing-library

test:

import {render, Simulate, wait} from 'react-testing-library'


import React from 'react';
import 'jest-dom/extend-expect'
import Todos from '../Todos';

const todos = [{
title: 'todo1'
},
{
title: 'todo2'
}];

describe('Todos', () => {
it('finds title', () => {
const {getByText, getByTestId, container} = render(<Todos todos={todos} />);
const elem = getByTestId('item');
expect(elem.innerHTML).toBe('todo1');
})

it('select todo', () => {


const {getByText, getByTestId, container} = render(<Todos todos={todos} />);
Simulate.click(getByText('Select'));
const elem = getByTestId('item');
expect(elem.classList[0]).toBe('selected');
})
});

Our last added test is using the Simulate helper to perform a click and we can see that
we are using the getByText helper to find the button. Thereafter we again use the
container to find and assert on the selected CSS class.

Asynchronous tests and working with input


We have so far shown you how to render a component, find the resulting elements and
assert on them. We have also shown how you can carry out things like a click on a button. In
this section we will show two things:

working with input


dealing with asynchronous actions

We will build the following:

Note.js , a component that allows us enter data and save down the results, it will also

allow us to fetch data


__tests__/Note.js , the test file

155
react-testing-library

Let's have a look at the component:

// Note.js
import React from 'react';

class Note extends React.Component {


state = {
content: '',
saved: '',
};

onChange = (evt) => {


this.setState({
content: evt.target.value,
});
console.log('updating content');
}

save = () => {
this.setState({
saved: `Saved: ${this.state.content}`,
});
}

load = () => {
var me = this;
setTimeout(() => {
me.setState({
data: [{ title: 'test' }, { title: 'test2' }]
})
}, 3000);
}

render() {
return (
<React.Fragment>
<label htmlFor="change">Change text</label>
<input id="change" placeholder="change text" onChange={this.onChange} />
<div data-testid="saved">{this.state.saved}</div>
{this.state.data &&
<div data-testid="data">
{this.state.data.map(item => (
<div className="item" >{item.title}</div>
))}
</div>
}
<div>
<button onClick={this.save}>Save</button>
<button onClick={this.load}>Load</button>
</div>
</React.Fragment>
);

156
react-testing-library

}
}

export default Note;

Working with input


To save data we need to enter data into an input and press the save button. Let's create a
test for that:

// __tests__/Note.js

import {render, Simulate, wait} from 'react-testing-library'


import React from 'react';
import 'jest-dom/extend-expect'
import Select from '../Note';

describe('Note', () => {
it('save text', async() => {
const {getByText, getByTestId, getByPlaceholderText, container, getByLabelText} =
render(<Select />);
const input = getByLabelText('Change text');

input.value= 'input text';


Simulate.change(input);
Simulate.click(getByText('Save'));

console.log('saved', getByTestId('saved').innerHTML);
expect(getByTestId('saved')).toHaveTextContent('input text')
})
});

We can see above that we use the helper getByLabelText to get a reference to our input
and we simply do input.value = 'input text' at that point. Thereafter we need to invoke
Simulate.change(input) for the change to happen. After that we can assert on the results by

typing expect(getByTestId('saved')).toHaveTextContent('input text')

Dealing with asynchronous


We have another piece of functionality in our component namely pressing a Load button
that invokes a load method, like so:

157
react-testing-library

load = () => {
var me = this;
setTimeout(() => {
me.setState({
data: [{ title: 'test' }, { title: 'test2' }]
})
}, 3000);
}

We can see above that the change doesn't happen straight away, this due to us using a
setTimeout . Having a look at our component we can see that we don't render out the data

property unless it is set to a value:

{this.state.data &&
<div data-testid="data">
{this.state.data.map(item => (
<div className="item" >{item.title}</div>
))}
</div>
}

Our test, we are about to write, needs to cater to this and wait for the div with attribute
data-testid="data" to be present before it can assert on it. Let's see what that looks like, by

adding a test to our test file:

158
react-testing-library

import {render, Simulate, wait} from 'react-testing-library'


import React from 'react';
import 'jest-dom/extend-expect'
import Select from '../Note';

describe('Note', () => {
it('save text', async() => {
const {getByText, getByTestId, getByPlaceholderText, container, getByLabelText} =
render(<Select />);
const input = getByLabelText('Change text');

input.value= 'input text';


Simulate.change(input);
Simulate.click(getByText('Save'));

console.log('saved', getByTestId('saved').innerHTML);
expect(getByTestId('saved')).toHaveTextContent('input text')
})

it('load data', async() => {


const {getByText, getByTestId, getByPlaceholderText, container} = render(<Select /
>);

Simulate.click(getByText('Load'));
await wait(() => getByTestId('data'))
const elem = getByTestId('item');
expect(elem).toHaveTextContent('test');
})

});

Above we see the construct await wait(() => getByTestId('data')) that halts until the
element is present. Thereafter we assert on the result.

Summary
We had a look at the library itself and wrote a few tests. We learned how to deal with events,
asynchronous actions as well as how to manage input. We covered most things this library
has to offer but more importantly we learned how to think about testing in a different way.

Maybe we don't have to test the internals but rather the surface of our components?

Further reading
There is a lot more to this library and you are encouraged to look at the

159
react-testing-library

Official documentation at:


Repository
And a blog post by its creator Kent C Dodds
Blog post

160
cypress

161
Redux - overview

Redux
Redux is about two things

managing a global data store also called state management


promoting a unform data flow

State management
A state in our app can exist inside a component but also in a global object. Typically state
that is only needed in one component should stay there. State that is used by more than one
component is usually put in a global store. Another thing we need to think about is that at
some point the state needs to be saved down, that's usually done by using performing an
AJAX call towards an endpoint.

When using a state management pattern here are the concerns:

what should go in there


how do we ensure that all components are in agreement what the state is
how do we ensure that state changes happen in the right order, some changes are
synchronous and some are asynchronous

Unidirectional data flow


A unidirectional data flow is about ensuring that data only flows in one direction. What do we
mean by that? Let's try to exemplify it by the following example.

We have two components, one create component and one list component. When an
item is created in the create component we want this information to reach the list
component. We don't want them to talk directly but rather indirectly. We usually solve
that by using a pub-sub, publish-subscribe pattern

We have our scenario and we are trying to define what should happen in what order:

User interaction, user enters values for a new item and presses a save button
The values are captured into a message and is being passed on, dispatched
A central store processes the message that leads to a change of its internal state
The central store then communicates out to all its listeners that the internal state has
changed, one such listener is our list component

162
Redux - overview

Why is this called unidirecitonal? Well the data in this case is only flowing in one direction.
We start with a user interaction and we end up with another UI component being updated.
What about other scenarios such as fetching initial data to our list component? Well in this
case we might have the following flow:

list component asks for data from the central store by sending it a message
central store in turn sends a message that leads to the data being fetched from an
endpoint via AJAX
when the data arrives the state of the central store is changed and an event is emitted
that a listener, in this case the list component is listening to

As you can see we communicate with messages that ends up being interpreted and leads to
a change of the state of our internal store. That change is broadcasted to a listener/s and the
UI gets updated

163
Actions

Actions
An Action is a message that we need to pass on to our centralized store. It carries the
intention of what we are trying to do as well as data, also called payload. An Action is usually
represented as an object

const action = { type: 'CREATE_ITEM', payload: 'my new item' };

The type is our intention and should be a verb saying what we are trying to achieve. The
payload carries our data and can be a string or an object or whatever best represents our

data.

Action creator
It is quite common to use something called an action creator. It is simply a function that
makes it easier for us to create our action object. It looks something like this:

const createItem = (newName) => ({ type: 'CREATE_ITEM', payload: { title: newName } })


;

164
Reducers

Reducer
A reducer is a function that is able to process our message, our Action. A reducer takes the
existing state and applies the message on it. The end result is a new state. A reducer
typically operates on a slice of state.

Defining a reducer
A reducer typically looks like this:

function reducer(state = [], action) {


switch(action.type) {
case 'CREATE_ITEM':
return [ ...state, { ... action.payload}];
case 'REMOVE_ITEM':
return state.filter(item => item.id !== action.payload.id);
default:
return state;
}
}

Using the reducer is done by invoking it:

let id = 1;
const actionCreator = (title) => ({ type: 'CREATE_ITEM', payload: { id: counter++, ti
tle } })

let state = reducer([], actionCreator('item1'));


// [{ title: 'item1' }]

state = reducer([], actionCreator('item2'));


// [{ title: 'item1' }, { title: 'item2' }]

What we can see above is how we can use the reducer and take initial state, and apply an
action to it. We also see how we can take an existing state and another action and simply
create a new state which consists of the old state + action .

Reducer Types

165
Reducers

There are different types of reducers. We have shown a list reducer so far but it is possible
to define reducers for:

lists
objects
primitives

Object reducer
We have already showcase the list reducer so let's have a look at an object reducer.

The aim of an object reducer is simply to either load the object or update parts of it, if we are
editing it for example. Let's show some code:

const reducer = (state = {}, action) => {


switch(action.type) {
case 'LOAD_ITEM':
case 'UPDATE_ITEM':
return { ...state, ...action.payload }
case 'REMOVE_ITEM':
return null;
}
}

Primitive reducer
This is quite an easy one. It looks like this if we are dealing with an integer:

const reducer = (state = 0, action) => {


switch(action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state -1;
default:
return state;
}
}

166
Store

Store
Well this all seems well and good but how does a reducer fit in with a having a global store
of data? Well reducers are used as the access point to our global state. It's a way to protect
the global state if you will. If we didn't use a reducer to manage our global state then
potentially anything could change and we would quickly loose control. Let's show how we
can let reducers handle our global state.

Imagine that we have a function dispatch that is our entry point for changing the global
state. Let's sketch it out:

const dispatch = (action) => {


}

Ok, so we take to inparameters action . The job of dispatch is to take an action and make
sure it finds the correct reducer and have that reducer calculate a new state. What we do we
mean by the right reducer? Well here is the thing. A reducer only operates on a slice of
state, it never manages the entire state. There is usually one reducer for our property of our
state object. Let us show this in code:

{
list: listReducer(state.list, action),
user: userReducer(state.user, action)
}

As you can see above we can connect every property of our state object with a reducer
function. Of course the above isn't valid code so what we need to do is to put this in a
function, like so:

const calc = (state, action) => {


return {
list: listReducer(state.list, action),
user: userReducer(state.user, action)
};
}

Now we can connect this to our dispatch function like so:

167
Store

const dispatch = (action) => {


state = calc(state, action);
}

As you can see above we also introduce a state variable that is nothing more than the
state of our store. It looks like this:

let state = {
list: [],
user: void 0
}

Our full code so far therefore looks like this:

let state = {
list: [],
user: void 0
}

const calc = (state, action) => {


return {
list: listReducer(state.list, action),
user: userReducer(state.user, action)
};
}

const dispatch = (action) => {


state = calc(state, action);
}

Now the above is the very engine in Redux. This is how we can send a message, have it
processed via a reducer and finally the state changes accordingly. There are of course other
things to this like:

ability to select a slice of state


notify listeners.

Select a slice of state


A component is not going to be interested in the entire state object but merely a slice of it. To
cater to this we need a select function that has the ability to select a slice of the object. That
is quite simple thing to do so let's add that to our code:

168
Store

const select = (fn) => {


return fn(state);
}

As you can see above we give it a parameter fn and end up return fn(state) and
thereby we let the input parameter decide what slice of state it wants. Let's showcase how
we can call the select method:

select((state) => state.list) // returns the list part only


select((state) => state.user) // returns the user part only

Notify listeners
Last but not least we need a way to communicate that our state has changed. This is easily
achieved by using letting a listener subscribe, like so:

let listeners = [];

const subscribe = (listener) => {


listeners.push(listener);
}

Then to notify all the listeners we need to call all these listeners when a change to our state
happens, we need to place some code in the dispatch :

const dispatch = (action) => {


state = calc(state, action);
listeners.forEach(l => l()); // calls all listeners
}

Ok so the full code now looks like this:

169
Store

// store.js

let state = {
list: [],
user: void 0
};

let listeners = [];

const listReducer = (state = [], action) => {


switch(action.type) {
case 'CREATE_ITEM':
return [ ...state, { ... action.payload}];
case 'REMOVE_ITEM':
return state.filter(item => item.id !== action.payload.id);
default:
return state;
}
};

const userReducer = (state = {}, action) => {


switch(action.type) {
case 'LOAD_USER':
case 'UPDATE_USER'
return { ...state, ...action.payload }
default:
return state;
}
}

const calc = (state, action) => {


return {
list: listReducer(state.list, action),
user: userReducer(state.user, action)
};
}

export const dispatch = (action) => {


state = calc(state, action);
listeners.forEach(l => l()); // calls all listeners
}

export const subscribe = (listener) => {


listeners.push(listener);
}

export const select = (fn) => {


return fn(state);
}

170
Store

Example
So far we have described how you can build a store from scratch. How do you use it in
practice though?

Imagine you have the following components:

create item component


list component

When a create item component is create a new item, it needs to express this as an action
and call dispatch on the store, like so:

171
Store

// create-action.js
export const createItem = (item) => ({ type: 'CREATE_ITEM', payload: { title: item } }
)

// create-item.js
import { createItem } from './create-action';
import { dispatch } from './store';

class CreateItem extends React.Component {


state = {
content: ''
}

create() {

onChange = (evt) => {


this.setState({
content: evt.target.value
});
}

onCreate = () => {
dispatch(createItem(this.state.content));
this.setState({
content: ''
})
}

render () {
return (
<React.Fragment>
<input onChange={onChange}>
<button onClick={onCreate}>Save</button>
</React.Fragment>
);
}
}

So much for the create-item component, what about the list component, how does it listen to
the store and how does it handle updates to the store?

172
Store

// list-component
import { select, subscribe } from './store';

class ListComponent extends React.Component {


state = {
list: []
}

componentDidMount() {
this.setState({
list: select((state) => state.list)
});
subscribe(this.update.bind(this));
}

update = () => {
console.log('store is updated');
this.setState({
list: select((state) => state.list)
});
}

render() {
return (
<React.Fragment>
<h3>My list</h3>
{this.state.list.map(item => <div>{item.title}</div>)}
</React.Fragment>
);
}
}

We answered both those questions with the code above, we initially fetch the store value we
care about in the componentDidMount like so:

this.setState({
list: select((state) => state.list)
});

we also listen to the store by calling subscribe and passing our update method like so:

subscribe(this.update.bind(this));

lastly when update is invoked we make sure to reread the state slice we care about by
calling it again, like so:

173
Store

this.setState({
list: select((state) => state.list)
});

174
Add Redux to React

Redux for React


defining the store
create presentation components, these are plain components that you are used to
creating
create container components, by using the connect() method on presentational
components

Get started
We need to install a couple of dependencies for this:

yarn add redux react-redux

Once we have those we are ready to begin

Adding Redux to React


We need to do the following to make it work:

create a store
expose the store with a Provider
create a container component

Creating a store
Creating a store is about creating the needed reducers, use a few helper functions and tell
Redux about it. Let's have a look at what creating the reducers might look like:

175
Add Redux to React

// store.js
import { combineReducers } from 'redux';

const listReducer = (state = [], action) => {


switch(action.type) {
case 'CREATE_ITEM':
return [ ...state, { ...action.payload }];
case 'REMOVE_ITEM':
return state.filter(item => item.id !== action.payload.id);
default:
return state;
}
};

const store = combineReducers({


list: listReducer
});

export default store;

Above we have only defined one reducer, in the same file as store.js no less. Normally we
would define one reducer per file and have them imported into store.js . Now we have
everything defined in one file to make it easy to understand, what is going on. One thing
worth noting is our usage of the helper function combineReducers . This is the equivalent of
writing:

const calc = (state, action) => {


return {
list: listReducer(state.list, action)
}
}

It's not an exact match but it is pretty much what goes on internally in combineReducers .

Expose the store via a provider


Next step is to wire everything up so we need to go to our index.js file and import our
store and expose it using a provider. We need to perform the following steps:

import createStore and invoke it to create a store instance


add the store to a Provider

First thing we do is therefore:

176
Add Redux to React

// index.js - excerpt
import { createStore } from 'redux';
import app from './store';

const store = createStore(app);

Next step is to wrap our root component App in a Provider and set its store property to
our newly created store, like so:

// index.js - excerpt

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'));

Add initial state


We can give our store an initial value, maybe there is some starter data that our app needs.
Initial value is added by calling dispatch on our store instance like so:

// index.js - excerpt

store.dispatch({ type: 'CREATE_ITEM', payload: { title: 'first item' } });

Full code
The full code with all the needed imports and calls looks like this:

177
Add Redux to React

// index.js

import React from 'react';


import { Provider } from 'react-redux';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { createStore } from 'redux'
import app from './store';

const store = createStore(app)


store.dispatch({ type: 'CREATE_ITEM', payload: { title: 'first item' } });

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'));
registerServiceWorker();

Accessing and changing data


Now we have a complete setup but we want to be able to access data by talking to the store,
same thing goes with if we want to alter data. The way we talk to the store is by introducing
the concepts container component and presentation component .

Container component
A container component is simply a component that contains the data and in this case has
knowledge of Redux. A presentational component relies fully on its inputs wether it is about
rendering data or invoking a method. Let's look at a non Redux example that shows this.

First let's define the presentational components:

178
Add Redux to React

const PresentationComponent = ({ todos }) => (


<React.Fragment>
{todos.map(todo => <div>{todo.title}</div>)
</React.Fragment>
);

const PresentationComponentInput = ({ add, onChange }) => (


<div>
Add a todo
<input onChange={onChange} />
<button onClick={add}>Add<button>
</div>
);

As you can see above the components are relying fully on input wether that input is pure
data to be rendered or functions to be invoked.

Next up let's define a container component, the component that sits on data and behavior:

class ContainerComponent extends React.Component {


state = {
todos: [
{ id: 1, title: 'clean' },
{ id: 2, title: 'dishwash' }
],
newItem
}

change = (ev) => {


this.setState({
newItem: ev.target.value,
})
}

add = (todo) => {


this.setState({
[ ...todos, { title: todo }],
newItem: ''
});
}

render() {
<React.Fragment>
<PresentationComponent todos={this.state.todos} />
<PresentationComponentInput onChange={this.change} add={add} />
</React.Fragment>
}
}

179
Add Redux to React

Above you can see how we have a state and methods that we pass on to the components
being rendered:

<React.Fragment>
<PresentationComponent todos={this.state.todos} />
<PresentationComponentInput onChange={this.change} add={add} />
</React.Fragment>

Redux
Ok, so we understand the basic idea. Applying this to Redux is about using a method called
connect that helps us create container components. Let's have a look what that looks like

in code:

const ListContainer = connect(


mapStateToProps,
mapDispatchToProps
)(List);

Above we can see how we invoke connect and we are able to create a ListContainer
component. There are three things here we need to explain though, namely:

mapStateToProps , this is function that returns an object of store states our component

should have access to


mapDispatchToProps , this is a function that returns an object with methods we should be

able to call
List , a presentation component

Let's look at each concept in close detail

mapStateToProps
It's job is to decide what data from the store we want to provide to a presentation
component. We only want a a slice of state, never the full application state. It for example
makes sense for a list component to have access to a list state but not a user for
example.

const mapStateToProps = (state) => {


return {
items: state.list
};
}

180
Add Redux to React

We can see above that we define a function that takes a state as parameter and ends up
returning an object. We can see that the returned object has a property items that gets its
value from state.list , this means we are reading the list property from the store and it
is being exposed as items .

mapDispatchToProps
This is a function the produces an object, when invoked. Let's have a look at its
implementation:

const addItem = (item) => ({ type: 'CREATE_ITEM', payload: { title: item } });

const mapDispatchToProps = dispatch => {


return {
onAddItem: item => {
dispatch(addItem(item))
}
};
}

Above we see that we take a dispatch method in. This method when called will allow us to
dispatch actions that leads to the stores state being changed. We define a onAddItem
method that when invoked will call on addItem method. It looks at first glance like we will
add an item that is ultimately going to be added to a list in a store.

ListContainer - container component


The full code for a container component therefore looks like this:

181
Add Redux to React

import React from 'react';


import {connect} from 'react-redux';

import List from '../components/List';

const addItem = (item) => ({ type: 'CREATE_ITEM', payload: { title: item } });

const mapStateToProps = (state) => {


return {
items: state.list
};
}

const mapDispatchToProps = dispatch => {


return {
onAddItem: item => {
dispatch(addItem(item))
}
};
}

const ListContainer = connect(


mapStateToProps,
mapDispatchToProps
)(List);

export default ListContainer;

List - presentation component


The List components source code looks like this:

182
Add Redux to React

// components/List.js

import React from 'react';


import styled from 'styled-components';
import PropTypes from 'prop-types';

import CreateItem from './CreateItem';

const Item = styled.div`


box-shadow: 0 0 5px;
margin-bottom: 10px;
padding: 20px;
`;

const ItemsContainer = styled.div`


margin: 10px;
`;

const Items = ({ items }) => (


<ItemsContainer>
{items.map(item => <Item>{item.title}</Item>)}
</ItemsContainer>
);

const NoItems = () => (


<div>No items yet</div>
);

const List = ({ items, onAddItem }) => (


<React.Fragment>
<CreateItem onAddItem={onAddItem} />
{items.length === 0 ? <NoItems /> : <Items items={items} />}
</React.Fragment>
);

List.propTypes = {
items: PropTypes.array,
};

export default List;

Just focusing on the rendering part of this component we see that it renders a list of data but
also have the ability to add an item:

const List = ({ items, onAddItem }) => (


<React.Fragment>
<CreateItem onAddItem={onAddItem} />
{items.length === 0 ? <NoItems /> : <Items items={items} />}
</React.Fragment>
);

183
Add Redux to React

What's interesting here is we see that it takes items and onAddItem as props . Now this is
exactly what the connect method does for us when it glues together Redux container
data/behaviour with a presentation component. Remember this from our container
component:

const ListContainer = connect(


mapStateToProps,
mapDispatchToProps
)(List);

The items property came from the object returned from mapStateToProps and onAddItem
came from mapDispatchToProps .

Make it work
What you end up rendering is container components like so:

// App.js

import React, { Component } from 'react';


import logo from './logo.svg';
import './App.css';
import ListContainer from './containers/ListContainer';

class App extends Component {


render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<ListContainer />
</div>
);
}
}

export default App;

Above we see how we render:

<ListContainer />

Our container component knows how to grab data from the store but also how to invoke
functions that adds/changes store data.

184
Add Redux to React

Summarising
Your app React/Redux is just more of the same. You will have a number of container
components and a number of presentation components and the connect() method is how
you ensure the presentation component renders data and is able to invoke a method that
leads to an action being dispatched and ultimately changes the stores state.

To see a fully working example of what's been described in this chapter please have a look
at this repo:
React Redux

185
Handling side effects with Sagas

Handling side effects with Sagas


So far when we have built our app using Redux we have worked in synchronous data.
Everything we do happens straight away wether we are incrementing a variable, adding an
item to a list and so on. A real app will most likely do asynchronous work, performing AJAX
requests when fetching and changing data. How would that look if we weren't using Sagas?

// some container component

const createAction = () => ({ type: 'CREATED' });

const loadAction = (data) => ({ type: 'LOAD_DATA', payload: data });

const mapDispatchToProps = (dispatch) => {


return {
add: (data) => {
const response = await fetch('url', {
method: 'POST',
body: JSON.stringify(data)
});
const responseData = response.json();
dispatch(createAction());
},
get: () => {
const response = await fetch('url');
const responseData = response.json();
dispatch(loadAction(responseData));
}
}
}

Ok, so above we see that we are defining a mapDispatchToProps and create two properties
on the object we return back, add and get . Now what happens inside them is that we use
some way to perform an AJAX call and when done we talk to Redux and our store by calling
dispatch .

We can definitely clean up the above a little so it doesn't look so bad but the fact remains we
are mixing AJAX communication with Redux. There is a way to handle this a bit more
elegantly namely by using Sagas.

So Sagas promises to create a bit more order. The idea with Sagas is that the only thing you
should see in a container component are dispatching of actions. Sagas acts as listeners to
specific actions. When a specific action happens the Saga will have the ability to intervene,

186
Handling side effects with Sagas

you can do its AJAX interaction and then end it all with dispatching an action.

Sounds simple enough right? Let's get started.

Installation & Setup


To use Sagas we need to install it by typing:

yarn add redux-saga

Next step is about telling Redux we want to use Sagas. Sagas are a so called middleware,
something that intercepts the normal Redux flow which means we need to do the following
to make Sagas work:

import and register Sagas as a middleware


create a saga
run a saga

import { createStore, applyMiddleware } from 'redux';


import createSagaMiddleware from 'redux-saga';
import { watchIncrementAsync } from './sagas';

Above we have imported applyMiddleware that we will need to register Sagas as a


middleware. Next thing we imported was createSagaMiddleware that we will use to create
the middleware. Lastly we import watchIncrementAsync which is simply our own written Saga
that intercepts a specific dispatch action of our choosing and carries out asynchronous work.

Next step is creating the middleware and registering it with Redux, like so:

const sagaMiddleware = createSagaMiddleware();


const store = createStore(
app,
applyMiddleware(sagaMiddleware)
)

As you can see we now give createStore a second parameter instead of just the root
reducer. That second parameter instructs Redux to run Sagas as a middleware.

Writing a Saga
We have one bit of set up left which is:

187
Handling side effects with Sagas

creating our saga


instruct our Saga to run, so it actively listens

For now we will create our handwritten Sagas in a file called sagas.js but as our project
grows we will need to break it down in many small files to make it maintable:

// sagas.js - excerpt

import { delay } from 'redux-saga'


import { put, takeEvery } from 'redux-saga/effects'

Above we add the needed imports in the form delay and put and takeEvery :

delay, this is really just a utility function that resolves a promise after x numver of
milliseconds
put, this is pretty much the dispatch of Sagas, you add an action as input parameter to
it.
takeEvery, this listens to a specific action type and runs a generator function in
response to a specific action occurring

Approach
Let's take a step back and think about what we are about to do. What we wan't to do and
what Sagas promise to help us with is to clean up the flow a bit when dealing with
asynchronous actions. To accomplish that a Saga has the following data flow to it:

listen to a specific action type


run a generator function in response to said action type
carry out asynchronous work in generator function
end generator function by calling put that dispatches an action and thereby leaves
back control to Redux.

Let's build a Saga with that flow in mind. Let's take something dead simple like incrementing
a number. I need you to imagine that this performs an AJAX request and when its done
resolves a Promise. Let's start with step one though, listening to a specific action:

// sagas.js - excerpt
export function* watchIncrementAsync() {
console.log("I'm hit first");
yield takeEvery('INCREMENT_ASYNC', incrementAsync)

188
Handling side effects with Sagas

Above we define the function watchIncrementAsync and we see that it calls takeEvery on
the action type INCREMENT_ASYNC . The second parameter of the function says what function it
should run in the response to this action occurring, namely incrementAsync . The above is
also called a watcher function.

Next step is about us creating and defining the function incrementAsync , so let's do that
next:

// sagas.js - excerpt

export function* incrementAsync() {


console.log("Then me - do async work here...");
yield delay(1000)
console.log('Done with async work, dispatch data');
yield put({ type: 'INCREMENT' })
}

We can see above that the first thing we do is to call yield delay(1000) , think of this as
writing:

await fetch(url);

What we mean by that is that this is the point where we should perform an AJAX call,
instead of writing await we use yield which is the corresponding keyword for generators.
Last thing to happen in this function is us calling put which dispatches an action and
thereby leaves control back to Redux. The full file looks like this:

import { delay } from 'redux-saga'


import { put, takeEvery } from 'redux-saga/effects'

// Our worker Saga: will perform the async increment task


export function* incrementAsync() {
console.log("Then me - do async work here...");
yield delay(1000)
console.log('Done with async work, dispatch data');
yield put({ type: 'INCREMENT' })
}

// Our watcher Saga: spawn a new incrementAsync task on each INCREMENT_ASYNC


export function* watchIncrementAsync() {
console.log("I'm hit first");
yield takeEvery('INCREMENT_ASYNC', incrementAsync)

189
Handling side effects with Sagas

As you can see above there isn't much to it. Let's repeat again the steps we need to take for
every Saga we write:

define a watcher function / listener that listens to a specific action


define a generator function, also called a worker saga that performs AJAX operations
or some other asynchronous work and end it all with a call to put to relinquish control.

Run the Saga


We have forgotten a little thing which is triggering the Saga to start watching. We need to
head back to our index.js file and do that:

// index.js - excerpt
sagaMiddleware.run(watchIncrementAsync)

Without this call, nothing will work, so don't forget it :)

Using it in the app


Using this in the app is about the following:

create a container component


dispatch an action that targets INCREMENT_ASYNC

Let's create that container component:

190
Handling side effects with Sagas

// IncrementContainer.js

import React from 'react';


import {connect} from 'react-redux';

import Increment from '../components/Increment';

const increment = () => ({ type: 'INCREMENT_ASYNC' });

const mapStateToProps = (state) => {


return {
value: state.value
};
}

const mapDispatchToProps = dispatch => {


return {
increment: () => {
dispatch(increment())
}
};
}

const IncrementContainer = connect(


mapStateToProps,
mapDispatchToProps
)(Increment);

export default IncrementContainer;

We can see above how we create the container component IncrementContainer by using
the presentation component Increment and augmenting it with the method increment and
the state value . We also see that upon invoking increment() we dispatch the action of
type INCREMENT_ASYNC .

For the presentation component we just need to wire up the increment method to a button
so we can invoke the method and thereby dispatch the action so our Saga will be targeted.
Let's define the presentation component:

191
Handling side effects with Sagas

// Increment.js

import React from 'react';

const Increment = ({ value, increment }) => (


<div>
Value: {value} &nbsp;
<button onClick={increment}>Increment</button>
</div>
);

export default Increment;

Further reading
There is a lot more to Sagas, have a read at the official docs Official docs

192
Redux Form

Redux Form
redux-form is a library that makes it easier to handle forms and make them fit into the

Redux system. Let's discuss briefly how we normally approach Forms without using this
library. Our approach is usually this:

state = {
value: ''
}

onSubmit = (evt) => {


// check the values, if ok, submit
}

onChange = (evt) => {


this.setState({
input: evt.target.value
})
}

render() {
return (
<form onSubmit={this.onSubmit}>
<div>
<input onChange={this.onChange} value={this.state.value}>
</div>
</form>
}

Above we show a few things we need to do work with forms, which is

keep track of when the value of inputs change, using onChange


respond to a submit, using onSubmit

There are other things we want to keep track of in a form like:

validating input, this is a big topic as it could be everything from checking wether an
input is there at all or matching some pattern or may even need to check on server side
wether something validates or not
check if its pristine, untouched, if so no need to validate and definitely we shouldn't
allow a submit to happen

Here is the good news, Redux Form library helps us with all these things, so let's show the
awesomeness of this library in this chapter.

193
Redux Form

Install and Set up


Installing it is as easy as typing:

yarn add redux-form

I'm assuming you already typed:

yarn add redux, react-redux

previously to get React working.

Setting it up is quite easy as well. What we need to do is to add some code in the file where
we create the root reducer. I usually create a store.js file like so:

// store.js

import { combineReducers } from 'redux'


import { reducer as formReducer } from 'redux-form'

const reducer = (state = 0, action) => {


switch(action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}

const rootReducer = combineReducers({


value: reducer,
})

export default rootReducer;

Above we have we a reducer function called reducer that we pass as a parameter to


combineReducers . We create an association so that the function reducer takes care of

value in the state of our store. To get redux-form to work we need to create the value

form and let a form reducer take care of it like so:

194
Redux Form

// store.js - excerpt
import { combineReducers } from 'redux'
import { reducer as formReducer } from 'redux-form'

// reducer definition

const rootReducer = combineReducers({


value: reducer,
form: formReducer,
})

export default rootReducer;

As you can see above we added the following line in our call to combineReducers :

form: formReducer

and formReducer comes from redux-form and is something we import, like so:

import { reducer as formReducer } from 'redux-form'

That concludes the set up we need to do, onwards to create a form component in our next
section.

Your first redux-form instance


Because this is Redux it means that we need to create the following:

a container component
a presentation component

There is a difference though, instead of using a connect function, to create our container
component, we will be using a function called reduxForm to achieve it. Let's create a simple
form and turn it into a redux-form :

195
Redux Form

// TodoForm.js - excerpt

import { Field, reduxForm } from 'redux-form';

class TodoForm extends Component {


render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="title">Title</label>
<Field name="title" component="input" type="text"/>
</div>
<button type="submit">Submit</button>
</form>
);
}
}

Ok, so now we have our presentation form and as you can see above we are passing a
handleSubmit function through our props . Another thing is the usage of Field component

that is an abstraction over any type of input that we want to create. In this case we use to
create a normal input tag but it can be made to represent any type of form field.

Let's turn into a container component. We do that by simply calling reduxForm , like so:

// TodoForm.js - excerpt

import { Field, reduxForm } from 'redux-form';

TodoForm = reduxForm({
form: 'todo' // a unique name for this form
})(TodoForm);

Aa you can see above we are calling reduxForm with an object that has the property form
that needs to have a unique value, so we give it the value todo . This is so our store can
differ between different forms when tracking its values. Let's first have a look at the full file
TodoForm.js before putting it in use:

196
Redux Form

// TodoForm.js

import React, { Component } from 'react';


import { Field, reduxForm } from 'redux-form';

class TodoForm extends Component {


render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="title">Title</label>
<Field name="title" component="input" type="text"/>
</div>
<button type="submit">Submit</button>
</form>
);
}
}

// Decorate the form component


TodoForm = reduxForm({
form: 'todo' // a unique name for this form
})(TodoForm);

export default TodoForm;

At this point let's put this in use. We will create a TodoPage component like so:

// TodoPage.js

import React from 'react';


import TodoForm from './containers/TodoForm';

class TodoPage extends React.Component {


handle = (values) => {
// Do something with the form values
console.log(values);
}
render() {
return (
<TodoForm onSubmit={this.handle} />
);
}
}

export default TodoPage;

197
Redux Form

What we can see above is how we render out the TodoForm component and we also assign
a function to its property onSubmit . Let's have a closer look at the handle method of our
component:

// TodoPage.js - excerpt

handle = (values) => {


// Do something with the form values
console.log(values);
}

Worth noting is how our input is the paraneter values that is an object representing our
form looking like so:

// values: { title: 'the value you typed' }

This is where redux-form has done its magic, in a normal form the input parameter on an
onSubmit for a form would be an event instead.

A more advanced example


Ok, so now you know how to get things set up and have created your first form. This library
comes pack with useful functionality so let's have a look at what you can do more.

Let's look at the following properties:

pristine, boolean saying where we interacted with the form at all


reset, function that allows us to reset the form to its previous state
submitting, boolean that determines wether we are submitting

Now back to our TodoForm.js , we will try to enhance it a little bit by adding the above
properties:

198
Redux Form

// TodoForm.js
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';

class TodoForm extends Component {


render() {
const { handleSubmit, pristine, reset, submitting } = this.props;
// rest of the form definition
}
}

// Decorate the form component


TodoForm = reduxForm({
form: 'todo' // a unique name for this form
})(TodoForm);

export default TodoForm;

We have omitted the form definition above to make it easier to see what we are doing. The
change consists of digging out pristine , reset and submitting from props . Now let's
add them to our form markup. Where should we add them though? Well we can pristine
and submitting on our button and disable the button if either of those properties are true.
It really makes no sense to allow a submit button to be pushed in the middle of submitting or
when the user hasn't even interacted with the form. Our markup therefore now looks like so:

// TodoForm.js - excerpt
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="title">Title</label>
<Field name="title" component="input" type="text"/>
</div>
<div>
<label htmlFor="email">Email</label>
<Field name="email" component="input" type="email"/>
</div>
<button disabled={ pristine || submitting } type="submit">Submit</button>
</form>

Especially look at the following:

<button disabled={ pristine || submitting } type="submit">Submit</button>

What about our last property, reset . Well this is a functionality that we can assign to a
button, like so:

199
Redux Form

<button onClick={reset} disabled={pristine}>


Reset
</button>

It makes sense to add the pristine condition to its disabled attribute as there is no point
resetting a form that hasn't been interacted with. Our form with some inputs now looks like
this:

Because we started to interact with the form you can see that the reset button is enabled.
Pressing reset button however leads to this:

200
Redux Form

Validating the form


Ok so now we know how to set things up, create a form with input fields and even check
things like pristine and so on. What about validation, validation is usually the topic where
we spend the most time implementing? Good news is that validation is pretty simple. It's as
simple as:

writing a validation function, and tell redux-form about it


customize the rendering of your input field to show validation errors, if any

Writing a validation function


Let's revisit our TodoForm.js file. We need to do the following for this to work:

provide a property validate to the object you give to reduxForm , this property should
point to a validation function that you need to write
define a custom input control where you are able to show your input as well as errors, if
there are any

Let's start off with the setup:

201
Redux Form

// TodoForm.js - excerpt

TodoForm = reduxForm({
form: 'todo',
validate
})(TodoForm);

As you can see above we are adding the property validate that points to a function
validate that we have yet to specify.

Remember validate: validate can be written as validate in ES6

Next step is defining the validate function which we can do like so:

const validate = values => {


}

Now what? Well this function is expected to return a dictionary of your errors. The input
parameter values contain all the field values so if you have a field title , values will
contain:

// { title: 'your entered value' }

Next up is therefore to implement the function validate :

const validate = values => {


const errors = {};

if (!values.title) {
errors.title = 'title must be entered';
}

return errors;
}

Above we have now defined the validate function. We go through the values input
parameter which is an object containing all of our field values. If we find that a certain values
isn't what it should be, like:

not existing
not conforming to a pattern then we create an entry in the dictionary errors with an
error message. The method validate will be invoked on each keyup event. Ok now
we have everything set up and we are ready to move on to the next bit which is how do
we display errors?

202
Redux Form

Customize an input
We have been using Field as the component that represents an input. So far we have set
an attribute component like so:

<Field name="title" component="input" />

We can give component a function as an argument instead of a string. This means that we
decide what gets rendered. Let's specify such a function:

const renderField = ({
input,
label,
type,
meta: { touched, error }
}) => {
return (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type} />
{touched &&
((error && <Error>{error}</Error>))}
</div>
</div>
)
}

What we see above is that renderField is function that takes an object as a parameter and
expects us to return a markup. Looking a little deeper at the input parameter we see that we
have the following interesting bits:

input, this is our input value


label, this is a text label
type, the type of input, given the value of this we an choose to render different types of
input components
meta, this is an object containing interesting information on the state of our input, if it
has been interacted with, if it has an error and so on.

Having a look at the markup, we see that we can lay out this input parameters to create a
nice looking input and a suitable place for our validation error:

203
Redux Form

(
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type} />
{touched &&
((error && <Error>{error}</Error>))}
</div>
</div>
)

Note, that we look on the property touched , which means if we interacted with the element
and based on it being in that state then we display the error:

{touched & ((error && <Error>{error}</Error>))}

Lastly we need to instruct our Field component to use this function, like so:

<Field name="title" component={renderField} />

Finishing up
We have defined our validation function. We have defined a function that let's create our
own representation of an input. Putting it all together our TodoForm.js should now look like
this:

// TodoForm.js

import React, { Component } from 'react';


import { Field, reduxForm } from 'redux-form';
import styled from 'styled-components';

const Error = styled.div`


color: red;
font-weight: bold;
margin: 5px;
padding: 10px;
margin-top: 0px;
`;

const FormContainer = styled.div`


margin: 20px;
box-shadow: 0 0 5px grey;
padding: 20px;

input {

204
Redux Form

border: solid 1px grey;


padding: 10px;
margin-bottom: 20px;
font-size: 16px;
}

button {
border: solid 1px grey
}
`;

const validate = (values) => {


const errors = {};
if(!values.title) {
errors.title ="title is required";
}

return errors;
}

const renderField = ({
input,
label,
type,
meta: { touched, error }
}) => {
return (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type} />
{touched &&
((error && <Error>{error}</Error>))}
</div>
</div>
)
}

class TodoForm extends Component {


render() {
const { handleSubmit, pristine, submitting, reset } = this.props;
return (
<FormContainer>
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="title">Title</label>
</div>
<div>
<Field name="title" component={renderField} type="text"/>
</div>
<div>
<label htmlFor="email">Email</label>
</div>

205
Redux Form

<div>
<Field name="email" component="input" type="email"/>
</div>
<button onClick={reset} disabled={ pristine } type="submit">Reset</button>
<button disabled={ pristine || submitting } type="submit">Submit</button>
</form>
</FormContainer>
);
}
}

// Decorate the form component


TodoForm = reduxForm({
form: 'todo',
validate
})(TodoForm);

export default TodoForm;

Further reading
There is a lot more to this wonderful library. Have a look at the official docs for more
advanced scenarios Official docs

206
Observables

Observables
TODO

207
Computed variables

Computed variables
TODO

208
Reactions

Reactions
TODO

209
storybook

Storybook
Imagine when your project grows and the number of components and developers with it. It
might get hard to keep track of all the components and how they are rendered differently
depending on what input they get. For those situations there exists a number of tools where
you can visually display your components - a style guide. This article is about one such tool
called Storybook.

Install & Setup


How would we install it? We need to install a CLI for this by typing:

npm i -g @storybook/cli

Once we have done so we can create our React project and from the project root we can
type:

getstorybook

This will install all the needed dependencies plus:

add a storybook-demo/.storybook/ directory


src/stories

add the following to package.json and the scripts tag: "storybook": "start-storybook -
p 9009 -s public"

The .storybook directory contains the following:

addons.js
config.js config.js tells storybook where our stories can be found. The stories
directory contains an index.js and stories which is something that storybook picks up
and renders as a HTML page.

The /stories/index.js looks like this:

210
storybook

import React from 'react';

import { storiesOf } from '@storybook/react';


import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';

import { Button, Welcome } from '@storybook/react/demo';

storiesOf('Welcome', module).add('to Storybook', () => <Welcome showApp={linkTo('Butto


n')} />);

storiesOf('Button', module)
.add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
.add('with some emoji', () => (
<Button onClick={action('clicked')}>
<span role="img" aria-label="so cool">

</span>
</Button>
));

Run
By running

yarn storybook

It will startup story book and we can navigate to http://localhost:9000 . It will look like this:

211
storybook

Let's look at the code that produces this in stories/index.js . Every call storiesOf('name of
module', module) produces a section. We can then chain a call to id add('name of component

variant', () => ()) . Now the add method is worth looking closer at:

.add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)

The second argument renders out a React component and we seem to be able to set
whatever property we want in there. Let's try to create a component and add it to
stories/index.js next.

Add a story
Let's do the following:

create a Todos.js component


add an entry of that component to stories/index.js

First off the code for Todos.js :

// Todos.js
import React from 'react';
import styled from 'styled-components';

const Todo = styled.div`


box-shadow: 0 0 5px grey;
padding: 10px;
margin-bottom: 10px;
`;

const Todos = ({ todos }) => (


<React.Fragment>
<h3>List of todos</h3>
{todos.map(t => <Todo key={t.title}>{t.title}</Todo>)}
</React.Fragment>
);

export default Todos;

Now let's add the entry to stories/index.js :

212
storybook

// stories/index.js

import React from 'react';

import { storiesOf } from '@storybook/react';


import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';

import { Button, Welcome } from '@storybook/react/demo';


import Todos from '../Todos';

import mocks from './mocks';

storiesOf('Welcome', module).add('to Storybook', () => <Welcome showApp={linkTo('Butto


n')} />);

storiesOf('Button', module)
.add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
.add('with some emoji', () => (
<Button onClick={action('clicked')}>
<span role="img" aria-label="so cool">

</span>
</Button>
));

storiesOf('Todos', module)
.add('with todos', () => <Todos todos={mocks.todos} />)

Let's highlight on our additions. First we import what we need:

import Todos from '../Todos';


import mocks from './mocks';

The mocks.js is a file we created to supply our components with data. We chose to place it
in a separate file so we don't clutter up index.js . The mocks.js is a very simple file
looking like this:

// stories/mocks.js
const mocks = {
todos: [{ title: 'test' }, { title: 'test2' }]
};

export default mocks;

Now back to our index.js file and let's look at the part where we set up our story:

213
storybook

storiesOf('Todos', module)
.add('with todos', () => <Todos todos={mocks.todos} />)

As you can see we set up the story and define a variant of that story by calling add . Let's
have a look at the result:

Improving - Dedicated story folders


Ok great now we know how to create our components and display them in a storybook.
However your storybook/index.js might become quite cluttered so you may want to opt for
a solution that scales better. Let's have a look .storybook/config.js :

import { configure } from '@storybook/react';

function loadStories() {
require('../src/stories');
}

configure(loadStories, module);

The loadStories function allows us to add more entries in there, which is perfect. Let's do
that:

import { configure } from '@storybook/react';

function loadStories() {
require('../src/stories');
require('../src/stories/common');
}

configure(loadStories, module);

As you can see we can now point out ../src/stories/common as yet another place our
stories can exist on. That directory now needs to consist of an index.js and we can write
our stories per usual like so:

214
storybook

// stories/common/index.js
import React from 'react';

import { storiesOf } from '@storybook/react';


import { action } from '@storybook/addon-actions';
import Button from '../../common/Button';

storiesOf('Button', module)
.add('with text', () => <Button title={'title for a button'}>text</Button>)
.add('with markup', () => <Button title={'title for a button'}><h3>My button</h3><sp
an>button text</span></Button>)

The component we render above has the following code:

import React from 'react';


import styled from 'styled-components';

const InnerButton = styled.button`


padding: 20px;
box-shadow: 0 0 5px grey;
border-radius: 3px;
:focus {
border: solid 1px black;
}
`;

class Button extends React.Component {


render() {
return (
<InnerButton { ...this.props } >{this.props.children}</InnerButton>
);
}
}

export default Button;

Our styleguide now renders like so:

215
storybook

and for the second button variant:

So if you start to have components divided up into different directories it can be a good idea
to bring that directory structure with you.

Further reading
Official docs Great article on different style guide for React

216
storybook

217
Joi - awesome code validation

Validating your data with the library Joi


Validation of data is an interesting topic we tend to write code that looks really horrible in the
sense that it contains a lot of checks like this:

if (!data.paramterX) {
throw new Exception('parameterX missing')
}

try {
let value = parseInt(data.parameterX);
} catch (err) {
throw new Exception('parameterX should be number')
}

if(!/[a-z]/.test(data.parameterY)) {
throw new Exception('parameterY should be lower caps text')
}

I think you get the idea from the above cringeworty code. We tend to perform a lot of tests
on our parameters to ensure they are the right type and/or their values contains the
allowed values .

218
Joi - awesome code validation

As developers we tend to feel really bad about code like this so we either start writing a lib
for this or we turn to our old friend NPM and hope that some other developer have felt this
pain and had too much time on their hands and made a lib that you could use.

There are many libs that will do this for you. I aim to describe a specific one called Joi.
Throughout this article we will take the following journey together:

Have a look at Joi's features


See how we can use Joi in the backend in a Request pipeline, yes we will try to build a
middleware for Express in Node.js
Look at ready made middleware, as fun as it is to build your own code, someone who
has already built one is great, they might have thought of edge cases you haven't and
you really don't have the time to build it, or do you?

Introducing Joi
Installing Joi is quite easy. We just need to type:

npm install joi

After that we are ready to use it. Let's have a quick look at how we use it. First thing we do is
import it and then we set up some rules, like so:

const Joi = require('joi');

const schema = Joi.object().keys({


name: Joi.string().alphanum().min(3).max(30).required(),
birthyear: Joi.number().integer().min(1970).max(2013),
});

const dataToValidate = {
name 'chris',
birthyear: 1971
}

const result = Joi.validate(dataToValidate, schema);

result.error // result.error == null means it's valid

What we are looking at above is us doing the following:

constructing a schema, our call to Joi.object() ,


validating our data, our vall to Joi.validate() with dataToValidate and schema as
input parameters

219
Joi - awesome code validation

Ok, now we understand the basic motions. What else can we do?

Well Joi supports all sorts of primitives as well as Regex and can be nested to any depth.
Let's list some different constructs it supports:

string, this says it needs to be of type string, and we use it like so Joi.string()
number, Joi.number() and also supporting helper operations such as min() and
max() , like so Joi.number().min(1).max(10)

required, we can say wether a property is required with the help of the method
required , like so Joi.string().required()

any, this means it could be any type, usually we tend to use it with the helper allow()
that specifies what it can contain, like so, Joi.any().allow('a')
optional, this is strictly speaking not a type but has an interesting effect. If you specify
for example prop : Joi.string().optional . If we don't provide prop then everybody's
happy. However if we do provide it and make it an integer the validation will fail
array, we can check wether the property is an array of say strings, then it would look
like this Joi.array().items(Joi.string().valid('a', 'b')
regex, it supports pattern matching with RegEx as well like so Joi.string().regex(/^[a-
zA-Z0-9]{3,30}$/)

The whole API for Joi is enormous. I suggest to have a look and see if there is a helper
function that can solve whatever case you have that I'm not showing above Joi API

Nested types
Ok so we have only showed how to declare a schema so far that is one level deep. We did
so by calling the following:

Joi.object().keys({

});

This stated that our data is an object. Then we added some properties to our object like so:

Joi.object().keys({
name: Joi.string().alphanum().min(3).max(30).required(),
birthyear: Joi.number().integer().min(1970).max(2013)
});

Now, nested structures are really more of the same. Let's create an entirely new schema, a
schema for a blog post, looking like this:

220
Joi - awesome code validation

const blogPostSchema = Joi.object().keys({


title: Joi.string().alphanum().min(3).max(30).required(),
description: Joi.string(),
comments: Joi.array().items(
Joi.object.keys({
description: Joi.string(),
author: Joi.string().required(),
grade: Joi.number().min(1).max(5)
})
)
});

Note especially the comments property, that thing looks exactly like the outer call we first
make and it is the same. Nesting is as easy as that.

Node.js Express and Joi


Libraries like these are great but wouldn't it be even better if we could use them in a more
seamless way, like in a Request pipeline? Let's have a look firstly how we would use Joi in
an Express app in Node.js:

221
Joi - awesome code validation

const Joi = require('joi');

// set up Express is omitted

app.post('/blog', (req, res, next) => {

// get the body


const { body } = req;

// define the validation schema


const blogSchema = Joi.object().keys({
title: Joi.string().required
description: Joi.string().required(),
authorId: Joi.number().required()
});

// validate the body


const result = Joi.validate(body, blogShema);
const { value, error } = result;
const valid = error == null;
if (!valid) {
res.status(422).json({
message: 'Invalid request',
data: body
})
} else {
const createdPost = await api.createPost(data);

res.json({
message: 'Resource created',
data: createdPost
})
}
});

The above works. But we have to define the schema call validate() on each request to a
specific route. It's, for lack of a better word, lacks elegance. We want something more slick
looking.

Building a middleware
Let's see if we can't rebuild it a bit to a middleware. Middlewares in Express is simply
something we can stick into the request pipeline whenever we need it. In our case we would
want to try and verify our request and early on determine wether it is worth proceeding with it
or abort it.

So let's look at a middleware. It's just a function right:

222
Joi - awesome code validation

const handler = (req, res, next) = { // handle our request }


const middleware = (req, res, next) => { // to be defined }

app.post(
'/blog',
middleware,
handler
)

It would be neat if we could provide a schema to our middleware so all we had to do in the
middleware function was something like this:

(req, res, next) => {


const result = Joi.validate(schema, data)
}

We should create a module with a factory function and module for all our schemas. Let's
have a look at our factory function module first:

const Joi = require('joi');

const middleware = (schema, property) => {


return (req, res, next) => {

const { error } = Joi.validate(req.body, schema);

const valid = error == null;


if (valid) {
next();
} else {

const { details } = error;


const message = details.map(i => i.message).join(',');
console.log("error", message);

res.status(422).json({
error: message
})
}
}
}

module.exports = middleware;

Let's thereafter create a module for all our schemas, like so:

223
Joi - awesome code validation

// schemas.js

const Joi = require('joi')

const schemas = {
blogPOST: Joi.object().keys({
title: Joi.string().required
description: Joi.string().required()
})
// define all the other schemas below
};

module.exports = schemas;

Ok then, let's head back to our application file:

// app.js

const express = require('express')


const cors = require('cors');
const app = express()
const port = 3000

const schemas = require('./schemas');


const middleware = require('./middleware');

var bodyParser = require("body-parser");


app.use(cors());
app.use(bodyParser.json());

app.get('/', (req, res) => res.send('Hello World!'))

app.post('/blog', middleware(schemas.blogPOST) ,function (req, res) {


console.log('/update');

res.json(req.body);
});

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

Testing it out
There are many ways to test this out. We could do a fetch() call from a browser console
or use cURL and so on. We opt for using a chrome plugin called Advanced REST Client .

Let's try to make a POST request to /blog . Remember our schema for this route said that
title and description were mandatory so let's try to crash it, let's omit title and see

what happens:

224
Joi - awesome code validation

Aha, we get a 422 status code and the message title is required , so Joi does what it is
supposed to. Just for safety sake let's re add title :

225
Joi - awesome code validation

Ok, happy days, it works again.

Support router and query parameters


Ok, great we can deal with BODY in POST request what about router parameters and query
parameters and what would we like to validate with them:

query parameters , here it makes sense to check that for example parameters like

page and pageSize exist and is of type number . Imagine us doing a crazy request

and our database contains a few million products, AOUCH :)


router parameters , here it would make sense to first off check that we are getting a

number if we should get a number that is ( we could be sending GUIDs for example )

and maybe check that we are not sending something that is obviously wrong like a 0
or something

Adding query parameters support

226
Joi - awesome code validation

Ok, we know of query parameters in Express that they reside under the request.query . So
the simplest thing we could do here is to ensure our middleware.js takes another
parameter, like so:

const middleware = (schema, property) => { }

and our full code for middleware.js would therefore look like this:

const Joi = require('joi');

const middleware = (schema, property) => {


return (req, res, next) => {

const { error } = Joi.validate(req[property], schema);

const valid = error == null;


if (valid) {
next();
} else {

const { details } = error;


const message = details.map(i => i.message).join(',');
console.log("error", message);

res.status(422).json({
error: message
})
}
}
}

module.exports = middleware;

This would mean we would have to have a look at app.js and change how we invoke our
middleware() function. First off our POST request would now have to look like this:

app.post('/blog', middleware(schemas.blogPOST, 'body') ,function (req, res) {


console.log('/update');

res.json(req.body);
});

with the added parameter body .

Let's now add the request who's query parameters we are interested in:

227
Joi - awesome code validation

app.get('/products', middleware(schemas.blogLIST, 'query'), function (req, res) {


console.log('/products');

const { page, pageSize } = req.query;


res.json(req.query);
});

As you can see all we have to do here is adding the argument query . Lastly let's have a
look at our schemas.js :

// schemas.js
const Joi = require('joi');

const schemas = {
blogPOST: Joi.object().keys({
title: Joi.string().required(),
description: Joi.string().required(),
year: Joi.number()
}),
blogLIST: {
page: Joi.number().required(),
pageSize: Joi.number().required()
}
};

module.exports = schemas;

As you can see above we have added the blogLIST entry.

Testing it out

228
Joi - awesome code validation

Let's head back to Advanced REST client and see what happens if we try to navigate to
/products without adding the query parameters:

As you can see Joi kicks in and tells us that page is missing.

229
Joi - awesome code validation

Let's ensure page and pageSize is added to our URL and try it again:

Ok, everybody is happy again. :)

Adding router parameters support


Just like with query parameters we just need to point out where we find our parameters, in
Express those reside under req.params . Thanks to the works we already done with
middleware.js we just need to update our app.js with our new route entry like so:

// app.js
app.get('/products/:id', middleware(schemas.blogDETAIL, 'params'), function(req, res)
{
console.log("/products/:id");
const { id } = req.params;
res.json(req.params);
})

At this point we need to go into schemas.js and add the blogDetail entry so schemas.js
should now look like the following:

230
Joi - awesome code validation

const Joi = require('joi');

const schemas = {
blogPOST: Joi.object().keys({
title: Joi.string().required(),
description: Joi.string().required(),
year: Joi.number()
}),
blogLIST: {
page: Joi.number().required(),
pageSize: Joi.number().required()
},
blogDETAIL: {
id: Joi.number().min(1).required()
}
};

module.exports = schemas;

Try it out

231
Joi - awesome code validation

Last step is trying it out so let's first test to navigate to /products/abc . That should throw an
error, we are only OK with numbers over 0:

232
Joi - awesome code validation

Ok, now for a URL stating /products/0 , our other requirement:

Also that fails, as expected.

Summary
We have introduced the validation library Joi and presented some basic features and how
to use it. Lastly we have looked at how to create a middleware for Express and use Joi in a
smart way.

All in all I hope this has been educational.

Further reading
Joi, official docs Official docs
exhaustive blog post on Joi validation, if you need more complex examples Blog post
Demo repository

My Twitter

233
Joi - awesome code validation

234

Das könnte Ihnen auch gefallen