Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Redux Quick Start Guide
Redux Quick Start Guide

Redux Quick Start Guide: A beginner's guide to managing app state with Redux

eBook
€13.98 €19.99
Paperback
€24.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Redux Quick Start Guide

Understanding Redux

With the great prevalence of web applications and companies transforming from traditional desktop-based systems to web-based systems, there are now a multitude of opportunities on the World Wide Web. There are various programming languages for server-side scripting (SSR), client-side scripting, presentation logic (HTML and CSS), and query languages. JavaScript is one of the most popular languages on the web, and it encompasses several frameworks that assist in its development, compilation, and production. React is one of the most popular JavaScript frameworks, and it is developed and distributed by Facebook. While React helps in building highly sophisticated, interactive user interfaces, Redux, on the other hand, is getting very popular in the frontend community for state management. In this chapter, we will get you familiarized with React, the concept of functional programming, the major components of Redux, and how to get started with it.

We will discuss the following topics in this chapter:

  • The need for Redux 
  • The concept of functional programming
  • The components of Redux
  • Getting started with Redux
  • Setting up the project

The need for Redux

The amalgamation of React and Redux is trending over the internet, but this popularity should not be a reason for using Redux in your application. Instead, you should be asking why you need Redux. What problems does it solve? A lot of technical books and blogs claim that Redux facilitates state management. That statement, in itself, is very vague. This is even vaguer a claim given that React also has state management. So, why should we use Redux in our applications?

React has a unidirectional data flow. The data is passed to a lower component by using props. For example, consider a simple state machine, as shown in the following screenshot:

The main component, App, holds the state of the machine and the props. The state status is passed down as the props, as follows:

In order to change the data up to the tree, a callback function must be passed as the props to any component that changes the state:

This is a normal scenario in any React application. When you keep building the application, more and more components are aggregated. Your application will react to the state; you will have layers of components, and the top layer will pass props to the child components. To understand this scenario, let's look at the example of Pinterest:

To achieve the layout shown in the preceding screenshot, we will require several components, and each component will need to pass props and states to its child components. A mocked-up version for different components would look something like the following snippet:

<App state={user: {}}>
<Navbar user = {user}>
<Logo />
<SearchBar />
<Menu> ... </Menu>
</Navbar>
<Content user={user}>
<TitleBar user={user} />
<Avatar user={user} />
<Board data={data} />
....
</Content>
<Footer />
</App>

In the preceding snippet, it is obvious that some props and states are used multiple times. For example, the Avatar component, the TitleBar component, and the Navbar component require user information. In order to deliver user information, each of the parent components must pass the props to their child components. It is possible to achieve this by passing the props; however, it will be cumbersome and painful if we have a bunch of components working together. By now it must be obvious that, when we work with React, we are dealing with a lot of components interacting with each other.

Instead of an intermediate component accepting and passing along the props, it would be nice if the component did not need to know about the data. This is the problem that is solved by Redux. It provides direct access to the required dataset. 

It is very intimidating to start coding your application. However, you can avoid a lot of hassle and debugging time if you can model your application. There are several tools that are available to model your application. If your model looks like the one in the preceding example, you can consider using Redux. If you feel the need to cache data between views and remember the data for the next layer, Redux is the best option. Finally, if you know that your application is large and your web application will deal with a large set of data that will fluctuate over time, Redux is a good option; it will help you to build an abstraction between the physical layer and the data layer.

Frequently asked questions

The following is a list of frequently asked questions about Redux:

  • Can I use Redux without React?
    Yes; Redux is an elegant library for state management. It can be used with any other library, including Vanilla JS, Angular, Vue JS, JQuery, Ember, Aurelia, and others.
  • Do I need Redux to build React applications?
    No; Redux facilitates managing the data layer in React applications. It really depends on the type of application that you are building. The amalgamation of React with Redux is very popular on the web, but you should really think about whether you need Redux. React already does state management, so using Redux for smaller applications will be overkill.
  • What do I need to use Redux?
    You will need ES6, ES5, or later versions.

Functional programming

A lot of blogs, books, online tutorials, videos, and courses found on the World Wide Web start with a common statement, saying that Redux was built on the top of functional programming. The statement is valid, which means that developers like us need to understand the concept of functional programming.

Let's point out some of the important characteristics of functional programming, as follows:

  1. Functions are first class objects
  2. Functions can be chained together
  3. Functions can be passed as arguments
  4. Functions, recursions, and an array can be used to control the flow
  5. We can use pure, higher-order, closure, and anonymous functions
  6. We can utilize several helper functions, including map, filter, and reduce

In functional programming, functions are considered first class citizens. This means that the language does support passing functions to other functions as arguments, and returning them as the values for other functions. Moreover, they can also be assigned to other variables, or stored in some data structure.

Assigning functions to variables

An example of calculating body mass index (BMI), provided the height (in meters) and weight (in kilograms), can be created via the following method. The function is stored in a variable named bmi and can be called whenever it is required:

const bmi = (weight, height) => weight / (height * height);

Adding functions to objects and arrays

A variable can be added to any object. Since a function is stored in a variable, it can also be added to objects, as follows:

const myCalculator = {
bmi: (weight, height) => weight / (height * height)
};

Similarly, we can add it to an array, as follows:

const myCalculator = [
Bmi => (weight, height) => weight / (height * height)
];

Functions as arguments

Functions can be used as arguments for other functions. Let's use the preceding bmi function to check whether a person has an obesity issue. According to the BMI scale, someone with a bmi between 30.0 and 54 is said to have obesity. We will pass a function as an argument, as follows:

const bmi = (weight, height) => weight / (height * height);
const hasObesity = (bmi) => bmi >= 30.0 && bmi <=54;
console.log(hasObesity(bmi(100, 2.2)));

Functions returned by functions

Another common scenario is when a function returns another function, as follows:

const bmi = (weight, height) => weight / (height * height);
const calculator = () => {
return bmi;
};

Higher-order functions

Higher-order functions (HOF is the fanciest term you will be hearing when getting started with functional programming. Higher-order functions are functions that take functions as arguments or return functions. By now, we have already been consuming such functions. Remember Array.reduce(), Array.filter(), and Array.map()? These are all higher-order functions. In the Redux library, we are consuming some of the HOF, too (such as connect()).

Pure functions

The most common definition of a pure function is a function that does not have side effects. This is to say that the returned value of a pure function is not affected, influenced, or changed by anything other than its input parameters. Provided the same input, the pure function always generates the same output. An example is as follows:

const sum = (a, b) => a + b;

This is an example of a pure function. Assuming that you call the function sum(6,9), the result is always 15, irrespective of the number of times that you run the function. You can be confident, if you are calling a pure function with the same input, that you are always going to get the same output, which means that the output is predictable. An example of an impure function is the following square function. In addition to returning the square of the number, the function might be updating the number in a database:

function square(number) {
updateNumberInDB(number);
return number * number;
}

Compositions

A composition is a very important concept of functional programming; it is how we create a higher-order function by consuming and combining simpler functions.

Let's just use the sum function that we defined previously. We can split the sum function into the following composition:

const sum = a => b => a + b
sum(2)(5)

Any function can be transformed into a composable function via the concept of currying. Explaining these fundamental functional concepts is beyond the scope of this book, and we suggest that you get familiar with functional terms as much as possible, in order to get a full understanding of Redux and React. We will consume a composition function from Redux, called compose, in upcoming chapters.

Fundamental principles of Redux

Redux makes it possible to store all statuses in an application in a single place, which is called a store. A store is the intermediary to all of the changes of the status of the app. Using Redux, a component cannot communicate directly with another component; instead, the changes always go through a single source, which is an action. Redux can be described simply by three fundamental principles. Those three main principles, which will be briefly explained in this chapter, are summarized as follows:

  • A single source of truth
  • The read-only nature of the state
  • The reducer principle

Single source of truth

The whole application state is stored in a single object, called the state tree. This makes it easier to create modern applications, as the server state can easily be serialized and hydrated to client apps.

An example for an online medical store app is as follows:

Read-only nature of the state

Emitting an action is the only way to change the state of a Redux app. Views cannot directly write to the state tree. In Redux, every intent needs to dispatch actions, which tell the reducers (a function) to transform the state. Mutating the state is also not recommended; hence, every time, the reducers write the existing state object with the new version:

The reducer principle – changes are made with pure functions

The transformation logic of the state tree is specified with the use of pure functions, called reducers. Reducers are special functions that take the current state and action to return a new state, without mutating the state.

The Redux ecosystem

When we talk about Redux, we usually include other libraries that work together in harmony. Here, we will discuss some of the important libraries that work well together, as follows:

  • react-redux: This allows us to communicate in both directions, between React and Redux (https://github.com/reactjs/react-redux). It is a binding between React and Redux that allows us to create containers and listen to the store changes, reflecting that into a presentational component. We will explore more about container components (smart components) and presentational components (dumb components) in upcoming chapters.
  • redux-devtools: This is the official implementation of developer tools for Redux, and it allows for watching state changes, live to edit actions, time traveling, and more (https://github.com/gaearon/redux-devtools).
  • redux-promise: This is middleware for Redux, allowing you to dispatch JavaScript promises to the Redux store (https://github.com/acdlite/redux-promise).

An official overview of the Redux ecosystem can be found on the Redux website, at http://redux.js.org/docs/introduction/Ecosystem.html.

There is a community-maintained repository called awesome Redux. This repository contains resources, libraries, utilities, boilerplate code, and examples associated with Redux, and is located at https://github.com/xgrommx/awesome-redux.

Elements of Redux

To understand Redux, we need to understand its components. There are four main elements of Redux; let's discuss each of them, one by one.

Actions

Actions are simply JavaScript objects describing the changes in the state of the application. To be specific, they are payloads of information that transfer data from our application to the state. Does this not make sense to you? No problem. Let's look at an example use case. Suppose that we need to add a doctor's information to our hospital management system:

const ADD_NEW_DOCTOR_REQUEST = "ADD_NEW_DOCTOR_REQUEST"

It isn't rocket science, right? It's just a simple, constant ADD_DOCTOR_REQUEST. Now, let's create an object:

{
type: ADD_NEW_DOCTOR_REQUEST,
data: {
name: ‘Dr. Yoshmi Mukhiya’,
age: 22,
department: ‘Mental Health’,
telecom: ‘99999999’
}
}

This is a simple, plain JavaScript object, and it is referred to as an action. An action must have the type property that defines the type of action to be performed. In this use case, the action is adding an action. The type is basically a string constant. In any web application, there are a multitude of actions required. So, the general (and most common) trend is to separate these actions into separate files and import them into the required place.

Now, let's assume that we need to delete a doctor's record from our app. We should be able to create an action object easily, as follows:

{
type: 'DELETE_DOCTOR_REQUEST',
identifier: 201,
}

Now, go ahead and create the actions for the following:

  1. Adding a user to the hospital management system
  2. Deleting a user from the hospital management system
  3. Updating a user

Action creators

JavaScript functions that take some arguments and return actions are action creators. Let's look at an action creator function for adding a new doctor to the application:

function addNewDoctor(data) {
return {
type: ADD_NEW_DOCTOR_REQUEST,
data
};
}

Now, you can think of a function that you might need for deleting a record, as follows:

function deleteDoctor(identifier) {
return {
type: "DELETE_DOCTOR_REQUEST",
identifier
};
}

Before we move on to reducers, let's make one more action creator for authentication. Generally, to authenticate, we use an email and password. So, in order to authenticate (or deauthenticate) we need to define actions. Please note that the actions that we define will be used in our project for a hospital management system. Our action for authentication could look something like the following:

export const authenticate = (credentials) => ({
type: "AUTHENTICATE",
payload: credentials
});
export const deauthenticate = () => ({
type: "DEAUTHENTICATE"
});

Similarly, let's create action creators for registering a user. When we register a user, we are likely to have a request, a success, or a failure. Based on these three states, we can create the action creators, as follows:

export const onRegisterRequest = user => ({ type: REGISTER_REQUEST, user });

export const onRegisterSuccess = user => ({ type: REGISTER_SUCCESS, user });

export const onRegisterFailure = message => ({
type: REGISTER_FAILURE,
message,
});

Reducers

JavaScript functions that take actions and states as input and return the new states are reducers. Well, if this is confusing, try to keep in mind that the action only describes what happened, not how the application state transforms.

It is very important to understand the reducer function. Let's consider our hospital management system. Our application's state can look like the following:

{
doctors: [
{
name: "John Doe",
department: "Radiology",
address: "Kathmandu, 4017, Nepal",
telecom: "999-999-999"
},
{
name: "Ola Nordmann",
department: "General Physician",
address: "Kong Oscarsgate 29, 5017, Bergen, Norway",
telecom: "111-111-1111"
}
];
}

When creating a reducer function, it is important that we remember the reducer principle: it must be a pure function. It should just take the action and return a new state, with no side effects, no mutations, and no API calls.

Let's consider another example of a content management system. In a normal CMS, we have posts and categories. So, our state at an instance could look like the following:

{
posts: [
{ user: 'John Doe', category: 'Practitioner', text: 'This is the first post about Practitioner.' },
{ user: 'Ola Nordmann', category: 'Patients', text: 'This is the first post about Patients.' }
],
filter: ‘Patients’
}

There's nothing complicated here, right? Now, let's start to write our reducer function for both use cases: our CMS use case and our hospital management system use case.

We will start by defining an initial state. Let's initiate our initial state by creating an empty object with an array of empty doctors:

const initialState = {
doctors: []
};

In any database, there is a need for creating, updating, reading, and deleting resources. Similarly, in the hospital management system, we need to read a doctor's record, create a new record, update it, or delete it. Hence, we are likely to have multiple action objects defined, as we mentioned in the preceding section.

This introduces a requirement to handle reducer functions for each of the actions. We can create a single reducer function to handle a similar scenario, and make use of the switch case to handle multiple action types:

import {
ADD_NEW_DOCTOR_REQUEST,
} from './actions'

function addDoctor(state = initialState, action) {
switch (action.type) {
case ADD_NEW_DOCTOR_REQUEST:
return Object.assign({}, state, {
doctors: [
...state.doctors,
{
name: action.name,
age: action.age,
department: action.department,
telecom: action.telecom
}
]
});
default:
return state;
}
}

In the preceding snippet, we have defined ADD_NEW_DOCTOR_REQUEST in the actions. We can check the action type for deleting the doctor's record. Go ahead and add a reducer use case for deleting a doctor.

Now, your task is to check the initial state of the CMS system and write reducer functions for CREATE_POST, EDIT_POST, and SET_FILTER. Once you have finished writing the reducer function, it should look something like the following:

import { CREATE_POST, EDIT_POST, SET_FILTER } from './actionTypes'

function postsReducer (state = [], action) {
switch (action.type) {
case CREATE_POST: {
const { type, ...post } = action
return [ ...state, post ]
}

case EDIT_POST: {
const { type, id, ...newPost } = action
return state.map((oldPost, index) =>
action.id === index
? { ...oldPost, ...newPost }
: oldPost
)
}

default:
return state
}
}

Store  

The store stores all of the states of the application. Hence, it is sometimes referred to as the heart of the application. The most important point to note is that there is a single store in the entire application. To create a store, we can use the createStore function provided by Redux:

import { createStore } from 'redux'
import doctorsReducer from './reducers'
const store = createStore(doctorsReducer)

The methods for stores will be explained in the following subsections.

getState()

The getState() method gives you the current state of any application, which is equal to the last value returned by the application's reducer.

dispatch(action)

As the name suggests, dispatch(action) only dispatches the action. The main point to keep in mind is that this is the single way to modify the state.

subscribe(listeners)

The subscribe(listeners) method adds a change listener, which is called any time an action is dispatched, and some part of the state tree may potentially have changed.

replaceReducer(nextReducer)

The replaceReducer(nextReducer) method replaces the reducer that's currently used by the store to calculate the state. It is an advanced API, and may not be required for normal use cases.

Redux life cycle

It is quite important to understand the Redux life cycle. To understand the Redux life cycle, you must understand the steps involved in a complete cycle. A user interacts with an interface through some events, like clicking on a button to create some resource. For example, to save a doctor record to a database, the user enters the relevant information and hits the Save button. These events initiate some actions. As we mentioned previously, an action is a pure JavaScript object that tells us what happened.

Redux confirms whether the dispatched action contains the type property. After the confirmation, it is passed the main reducer. This is referred to as dispatching an action. An action is dispatched using the following function:

store.dispatch(action)

The entire concept of how Redux operates is illustrated in the following diagram:

The main reducer function, when called with the current state and dispatched action, passes the sub-states and action down to another reducer. As we mentioned in the previous section, the reducer is just a function, and it uses the previous state and provides the new state. Developers prefer to split the state tree into multiple slices and create a separate reducer for each state slice. Actions, on the other hand, can be concerned with more than one state slice. This method of splitting the reducers into smaller and easier to understand pieces is termed decomposition.

The new state is returned by the main reducer function and is saved in the Redux store, and all listener functions that are subscribed via store.subscribe() get called. This causes the re-render of user interfaces. We will look at the concept of Redux middleware more in Chapter 6, Extending Redux by Middleware.

So far, we have gone over a lot of theoretical concepts. If it does not make sense entirely, do not worry. It takes some time to sync with the concepts and the flow. To get better insight into how this works, let's get started with the very basic concept of making your first Redux Hello World application.

Getting started

Let's get started with using Redux. We will start with basic configurations, and we can take the configurations further in each chapter:

  1.  Installing node and npm/yarn is done as follows:

Install the latest version of a node from https://nodejs.org/. To verify the correct installation, run the following command:

node --version

You can get the latest version of yarn from https://yarnpkg.com/en/, and npm from https://www.npmjs.com/get-npm.

  1. Initialize the project as follows:

The first thing is to initialize the project. In this project, we are going to use yarn. The easiest way to initialize the project with package.json is to run the init command:

yarn init
OR
npm init

Follow the onscreen instructions and provide the details. It will ask about the name of the project, the description, the author name, the version, the license, and the entry point. Most of the information can be customized according to your requirements.

Now, create a source folder, src, to include all of our code. The next step is to set up webpack. The minimal package.json file looks like the following:

{
"name": "gettting-started-with-redux-ch01",
"version": "1.0.0",
"description": "Getting Started With Redux",
"main": "src/app/app.js",
"scripts": {
"start": "webpack-dev-server",
"build": "webpack"
},
"author": "Suresh KUMAR Mukhiya",
"license": "MIT",
"devDependencies": {
"@babel/core": "7.2.0",
"@babel/preset-env": "7.2.0",
"@babel/preset-react": "7.0.0",
"babel-core": "6.26.3",
"babel-loader": "8.0.4",
"babel-plugin-transform-object-rest-spread": "6.26.0",
"webpack": "4.27.1",
"webpack-cli": "3.1.2",
"webpack-dev-server": "3.1.10"
},
"dependencies": {
"redux": "4.0.1"
}
}
  1. Configuring webpack is done as follows:

You can read more about webpack on their official documentation site (https://webpack.js.org/). The first thing is to install webpack and webpack-dev-server:

yarn add webpack webpack-dev-server --dev

Now, we need to configure the webpack. We can do that in different ways. A lot of information about webpack configuration can be found on the documentation site (https://webpack.js.org/configuration/). The minimum configuration that we need is as follows:

const path =require('path')
module.exports ={
Mode: ‘development’,
entry:'./app/app.js',
output: {
path: path.resolve('dist'),
filename: 'main.js'
},

Let's place the webpack configuration files into the webpack folder and create a base configuration file, called webpack.config.js. The loaders in the webpack tell the webpack what to do with the entry file(s). We are going to use Babel to transpile our JavaScript files; so, let's define the babel-loader for .js files, as follows:

const path = require("path");
module.exports = {
mode: "development",
entry: "./src/app/app.js",
output: {
path: path.resolve("dist"),
filename: "main.js"
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
}
]
}
};

Generally, what we have is the bare minimum code required for Webpack configuration. However, in a real application, we would like to compile more resources than just the JavaScript files, including JS files, CSS files, fonts, image files, and others. We can configure these with webpack.

The most standard practice is to split the configuration into two types: development configuration and production configuration. By now, you might have already realized the need for separate configurations. A detailed blog article about this need and its process can be found at https://www.hacksoft.io/blog/split-your-webpack-configuration-development-and-production/. To keep the configuration simple and elegant, we have created three files for webpack; namely, webpack.base.babel.js, webpack.dev.babel.js, and webpack.prod.babel.js. You can find a similar configuration in the starter file in the GitHub repository.

  1. Babel is configured as follows:

We will use Babel to compile JavaScript files. Let's configure it by installing babel and its related libraries:

yarn add @babel/core @babel/preset-env @babel/preset-react babel-core babel --dev --exact
yarn add babel-loader babel-plugin-transform-object-rest-spread --dev --exact

More configuration related to Babel can be found at https://babeljs.io/docs/usage/api/#options.

For the minimum configuration, we will go with creating a babel.config.js file and adding an entry, as follows:

module.exports = {
presets: [
[
"@babel/preset-env",
{
modules: false
}
],
"@babel/preset-react"
],
plugins: ["transform-object-rest-spread"]
};

This file just indicates which libraries we are using in order to compile our JavaScript files. For example, we are going to use a transform-object-rest-spread library to utilize the spread feature. Learn more about this library at https://babeljs.io/docs/en/babel-plugin-proposal-object-rest-spread. We can add other polyfill plugins that we plan to use throughout the project later on. Babel can be configured in multiple ways. We can also create a .babelrc file to configure it. You will find a working example in Chapter 2, Testing.

  1.  Define the entry file:

The entry file indicates the startup file. We will point our entry file to app/app.js. This file contains the main entry codes. This file will be transpiled into main.js by Babel. Secondly, we will create an index.html file, which acts as the entry file for our application:

<!doctype html>
<html lang="en">
<head>
<!-- The first thing in any HTML file should be the charset -->
<meta charset="utf-8">
<!-- Make the page mobile compatible -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Allow installing the app to the homescreen -->
<meta name="mobile-web-app-capable" content="yes">
<link rel="icon" href="/favicon.ico" />
<title>Redux-Book-starter</title>
</head>
<body>
<div id="root"></div>
</body>
<script src="dist/main.js"></script>
</html>

Also, inside of the app/app.js, we can try to log some text to verify that the configuration is working fine:

console.log("Welcome to Redux Programming");

Now, the last step is to configure the webpack script to run the build. This can be done by placing scripts in the package.json file:

"scripts": {
"start": "webpack-dev-server",
"build": "webpack"
},

The first step is to build the files. To do that, simply run yarn build from your command line. Now, we can run the webpack by using the yarn start command from the command line. Note that this is the minimum configuration required to get started with Redux. Our aim here is for you to learn Redux. So, we are going to use starter files for each of the projects, which can be found in the GitHub repository for this book. The starter files, if preconfigured with Babel, Webpack, and Eslint, are ready to be consumed for further development.

  1. Installing Redux:

To get started with Redux, we need to add Redux to our dependencies list, as follows:

yarn add redux --exact

Now, from the project root folder, inside of your command line, run yarn start and open http://localhost:8080 in your favorite browser, checking the console. You should see the log we have in your app/app.js.

Understanding Redux methods

Let's implement a simple example to turn on and turn off the light. We can build a simple robot that just listens to commands and, based on the commands, performs some actions. For simplicity, suppose that our robot can only understand two commands, as follows:

  1. TURN_ON
  2. TURN_OFF

Now, let's build our robotic function:

const tubeLight = (state = "OFF", action) => {
switch (action.type) {
case "TURN_ON":
return "ON";
case "TURN_OFF":
return "OFF";
default:
return state;
}
};

This is a simple JavaScript function that takes the initial state and action as parameters and returns a state. That sounds like something familiar, doesn’t it? Yup; you are right. This is a simple reducer function.

In the first section, you learned Redux's first principle: a single source of truth. Redux provides a function called createStore that takes the main reducer file and creates the store. Let's create a store, as follows:

import { createStore } from "redux";
const store = createStore(tubeLight);

So far, so good. So, what did we do here? We imported the createStore function from the Redux library that is given tubeLight, which is a reducer, as an argument and is saved into a variable called a store. Here, you can recall a functional programming concept. A function can consume another function. Now, as you have already seen, the store has three methods: getState, dispatch, and subscribe. Let's use them.

log the initial state, as follows:

console.log("Initially tubelight is: ", store.getState());

Try to build it, and run it again (yarn build && yarn start). Check the console:

Initially tubelight is:  OFF

Nothing complex, right? We provided the initial state to OFF, and it logged the initial state as OFF. That looks good. Now, let's try to modify the store. In other words, we should instruct the robot to turn on the tubelight. Remember, we can only modify the store by using a dispatch function. Now, we can use that function and log the state, in order to see the state change:

store.dispatch({ type: "TURN_ON" });
console.log("Now tubelight is: ", store.getState());

The output that you get on the console should be as follows:

Now tubelight is:  ON

Now, it makes sense, right? Let's go further and display the state on the browser, rather than on the console. To do that, let's create a button. When we press the button, it should toggle the tubelight state. That is to say, if the tubelight is ON, we turn it off, and vice versa. To make it simple, let's forget about React and use native JavaScript:

const button = document.createElement("button");
button.setAttribute("id", "lightButton");
var text = document.createTextNode("Toggle Light");
button.appendChild(text);
document.body.appendChild(button);

The preceding snippet will create a simple button on the browser, with the text Toggle Light and the ID lightButton.

Now, we need to add an event listener. That is to say, if the tubelight is on, we turn it off by clicking on the button. We can do that as follows:

document.getElementById("lightButton").addEventListener("click", () => {
if (store.getState() === "ON") {
store.dispatch({ type: "TURN_OFF" });
} else {
store.dispatch({ type: "TURN_ON" });
}
});

Now, let's render that in the browser, inside of the body tag:

const render = () => {
document.body.innerText = store.getState();
document.body.appendChild(button);
};

This will render the initial state of the store. But we need to display when the state changes. To do that, our third method of the store comes into play (subscribe()):

store.subscribe(render);
render();

Now, try to build the app and run it (yarn build && yarn start). Try to click on the button to change the state, and see whether the state is reflected on the browser. Pretty sweet, right? You can find the working example of this code in the GitHub repository, inside CH01/getting-started.

Manually updating the DOM does not scale in a real application. To do so, we use the help of other libraries, such as React. We will configure React with Redux and use it to understand other complex scenarios in Redux.

Setting up the project

Having understood the concept of Redux, let's get started with the project that we promised to work with. We will continue to use the project from the getting-started section to build the other components required for the project. Throughout this entire book, we will develop a multilingual hospital management system. Of course, the development of a complete hospital management system is out of the scope of this book, but we are going to get started with a simple one. We are going to have an authentication system and a CRUD (Create, Read, Update, and Delete) of users to get started with.

Configuring the store

Since we know what a store is in Redux, let's get started with creating a store file. We can keep our store in a separate file. Let's call it configureStore.js:

import { createStore, applyMiddleware, compose } from "redux";

import createReducer from "./reducers";

export default function configureStore(initialState = {}, history) {
const store = createStore(
createReducer(),
);

// Extensions
store.injectedReducers = {}; // Reducer registry

return store;
}

Configuring the root reducer

Our root reducers can reside in a reducers.js file. We are going to use the combinedReducers utility function from the Redux library:

import { combineReducers } from "redux";

import history from "utils/history";

export default function createReducer(injectedReducers = {}) {
const rootReducer = combineReducers({
...injectedReducers
});
return rootReducer;
}

Configuring our app with Redux

This is the main file, app.js, which will be the main entry file for our project. We are going to put the file inside of app/app.js. You can see that we are using some of the npm packages, including @babel/polyfill, react, react-dom, react-redux, and sanitize.css:

// Needed for redux-saga es6 generator support
import "@babel/polyfill";

// Import all the third party stuff
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import history from "utils/history";
import "sanitize.css/sanitize.css";

// Import root app
import App from "containers/App";

import configureStore from "./configureStore";

// Create redux store with history
const initialState = {};
const store = configureStore(initialState, history);
const MOUNT_NODE = document.getElementById("app");

const render = () => {
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
MOUNT_NODE
);
};

render();

Let's briefly go over these packages, as follows:

  • @babel/polyfill (https://babeljs.io/docs/en/babel-polyfill): Babel polyfill has a polyfill that contains a custom regenerator runtime and core-js. In other words, it allows us to consume the full set of ES6 features, beyond syntax changes, including built-in objects like Promises and WeakMap, as well as new static methods, like Array.from or Object.assign.
  • react: We already know what React is. We are going to dive deeper into creating React components in Chapter 6, Extending Redux by Middleware.
  • react-dom: React DOM helps us to glue React and the DOM. When we want to show our React components on the DOM, we need to utilize this ReactDOM.render() function from React DOM. We will discuss these features more in the upcoming chapters.
  • React-redux: This allows us to communicate, in both ways, between React and Redux (https://github.com/reactjs/react-redux). It is a binding between React and Redux that allows us to create containers and listen to the store changes, reflecting that into a presentational component. We will explore container components (smart components) and presentational components (dumb components) in more detail in upcoming chapters.
  • Sanitize.css (https://github.com/csstools/sanitize.css): This is one of the cascading style sheet libraries that yield consistent, cross-browser default styling of HTML elements, as well as useful defaults.

Creating utilities

We used a history object in app.js. We can create history.js inside of the utils folder and create an instance of history. You can learn more about history from https://github.com/ReactTraining/history. In a nutshell, the history library manages the session history everywhere that JavaScript runs:

import createHistory from "history/createBrowserHistory";
const history = createHistory();
export default history;

Creating the first container

Let's create our first container component, inside of app/containers/App/index.js:

import React from 'react';
import HomePage from 'containers/HomePage/Loadable';
export default function App() {
return (
<div>
<HomePage />
</div>
);
}

The home page container contains two files, Loadable.js and index.js:

import loadable from 'loadable-components';
export default loadable(() => import('./index'));

The index.js is as follows:

import React, { PureComponent } from 'react';
/* eslint-disable react/prefer-stateless-function */
export default class HomePage extends PureComponent {
render() {
return <h1>This is the HomePage Redux-book container!</h1>;
}
}

The complete code for this project can be found in the GitHub repository, inside of the CH01 starter files. We are going to continue using it in other chapters. Once you have these files up in your editor, we can start to run our first application. To run the application, the first thing to do is install the npm dependencies, as follows:

yarn install
yarn run

The application should start at http://localhost:8080/.

Summary

Redux is one of the most popular libraries used for state management in the frontend ecosystem today. In this chapter, we discussed the need for Redux and the principles that make the library stand out. Moreover, we discussed some of the fundamental concepts of functional programming, and how these concepts are used in the development of the Redux library. We also covered some of the Redux ecosystem and the Redux life cycle, and we created an outline for the project. We implemented the bare minimum version of Redux, extending it to create a larger project.

In the next chapter, you will learn about test-driven development, and we will set up the JEST framework for testing. Moreover, we will continue to use the code that we developed in this chapter in the upcoming chapters.

Further study

We outlined the basic architecture of Redux and its ecosystem in this chapter. However, we are aware of the fact that it is not easy to understand everything in one go. The following is a list of resources that you can consider to get further knowledge:

  1. https://redux.js.org/.
  2. Learning Redux, by Daniel Bugl, August 2017, Packt Publications.
  3. https://babeljs.io/docs/en/.
  4. React: Tools and Resources, by Michael Wanyoike; Manjunath, M.; Jack Franklin; Swizec Teller; and Ahmed Bouchefra.
  1. Learning React: Functional Web Development with React and Redux, by Alex Banks and Eve Porcello.
  2. Abelson, Harold; Sussman, Gerald Jay (1984). Structure and Interpretation of Computer Programs. MIT Press. Section 1.3, Formulating Abstractions with Higher-Order Procedures. ISBN 0-262-01077-1.
  3. Mukhiya, S. K. and Hoang Hung, K. (2018). An Architectural Style for Single Page Scalable Modern Web Applications, 5(4), 6–13. Retrieved from https://www.ijrra.net/Vol5issue4/IJRRA-05-04-02.pdf.
Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Get better at building web applications with state management using Redux
  • Learn the fundamentals of Redux to structure your app more efficiently
  • This guide will teach you develop complex apps that would be easier to maintain

Description

Starting with a detailed overview of Redux, we will follow the test-driven development (TDD) approach to develop single-page applications. We will set up JEST for testing and use JEST to test React, Redux, Redux-Sage, Reducers, and other components. We will then add important middleware and set up immutableJS in our application. We will use common data structures such as Map, List, Set, and OrderedList from the immutableJS framework. We will then add user interfaces using ReactJS, Redux-Form, and Ant Design. We will explore the use of react-router-dom and its functions. We will create a list of routes that we will need in order to create our application, and explore routing on the server site and create the required routes for our application. We will then debug our application and integrate Redux Dev tools. We will then set up our API server and create the API required for our application. We will dive into a modern approach to structuring our server site components in terms of Model, Controller, Helper functions, and utilities functions. We will explore the use of NodeJS with Express to build the REST API components. Finally, we will venture into the possibilities of extending the application for further research, including deployment and optimization.

Who is this book for?

This book is meant for JavaScript developers interesting in learning state management and building easy to maintain web applications.

What you will learn

  • Follow the test-driven development (TDD) approach to develop a single-page application
  • Add important middleware, such as Redux store middleware, redux-saga middleware, and language middleware, to your application
  • Understand how to use immutableJS in your application
  • Build interactive components using ReactJS
  • Configure react-router-redux and explore the differences between react-router-dom and react-router-redux
  • Use Redux Dev tools to debug your application
  • Set up our API server and create the API required for our application
Estimated delivery fee Deliver to Luxembourg

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Feb 28, 2019
Length: 204 pages
Edition : 1st
Language : English
ISBN-13 : 9781789610086
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Luxembourg

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Publication date : Feb 28, 2019
Length: 204 pages
Edition : 1st
Language : English
ISBN-13 : 9781789610086
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 90.97
React Design Patterns and Best Practices
€32.99
React Material-UI Cookbook
€32.99
Redux Quick Start Guide
€24.99
Total 90.97 Stars icon

Table of Contents

9 Chapters
Understanding Redux Chevron down icon Chevron up icon
Testing Chevron down icon Chevron up icon
Routing Chevron down icon Chevron up icon
The Concept of Immutability Chevron down icon Chevron up icon
React with Redux Chevron down icon Chevron up icon
Extending Redux with Middleware Chevron down icon Chevron up icon
Debugging Redux Chevron down icon Chevron up icon
Understanding the REST API Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Empty star icon Empty star icon 3
(1 Ratings)
5 star 0%
4 star 0%
3 star 100%
2 star 0%
1 star 0%
Chico W Sep 01, 2021
Full star icon Full star icon Full star icon Empty star icon Empty star icon 3
I really wanted this book to be great. I needed a reference on redux and redux-saga. Unfortunately, this book is all over the place, introducing concepts unrelated to redux. There are a few valuable concepts presented, but not enough for me to recommend this book to anyone.
Amazon Verified review Amazon