Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Redux Quick Start Guide

You're reading from   Redux Quick Start Guide A beginner's guide to managing app state with Redux

Arrow left icon
Product type Paperback
Published in Feb 2019
Publisher Packt
ISBN-13 9781789610086
Length 204 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Authors (3):
Arrow left icon
Suresh Kumar Mukhiya Suresh Kumar Mukhiya
Author Profile Icon Suresh Kumar Mukhiya
Suresh Kumar Mukhiya
Tao Wei Tao Wei
Author Profile Icon Tao Wei
Tao Wei
James Lee James Lee
Author Profile Icon James Lee
James Lee
Arrow right icon
View More author details
Toc

Table of Contents (10) Chapters Close

Preface 1. Understanding Redux 2. Testing FREE CHAPTER 3. Routing 4. The Concept of Immutability 5. React with Redux 6. Extending Redux with Middleware 7. Debugging Redux 8. Understanding the REST API 9. Other Books You May Enjoy

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.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime