13. Use Redux To Store Data

13.1. Introduction

Currently we have the state of the FAQ list in the App component and pass all handlers and data down to the FaqItem component. When your application will contain more subcomponents, this can become very complex. To manage your application state, we will introduce Redux here. Redux is a state management system which is composed of a store. This store contains data, a set of reducers which handle (part of) this state and its changes, and actions which are used to trigger state changes.

A reducer is pure function which takes the previous state and an action, and returns a new state based on the data of the action. The new state is then saved to the store. Components can then read data from the store and render a view. When a change needs to be made to the application state, the view will fire an action which will be handled by the reducer again, and so on. This is a unidirectional flow.

13.2. Installing

To install Redux, we will run the following command:

yarn add redux react-redux

13.3. Actions

We will start by creating actions. We will create a file actions/index.js with the addFaqItem action:

1export const addFaqItem = (question, answer) => ({
2  type: "ADD_FAQ_ITEM",
3  question,
4  answer
5});

Write the editFaqItem and deleteFaqItem actions.

Solution

 7export const editFaqItem = (index, question, answer) => ({
 8  type: "EDIT_FAQ_ITEM",
 9  index,
10  question,
11  answer
12});
13
14export const deleteFaqItem = index => ({
15  type: "DELETE_FAQ_ITEM",
16  index
17});

13.4. Reducers

Next we will create the reducer by creating the reducers/faq.js file. As stated earlier, a reducer is a pure function which takes the previous state and an action, and returns the new state. It will look like this:

1const faq = (state = [], action) => {
2  // Do something
3};
4
5export default faq;

Finish the reducer so that it can handle the ADD_FAQ_ITEM, EDIT_FAQ_ITEM, and DELETE_FAQ_ITEM actions.

Solution

 1const faq = (state = [], action) => {
 2  let faq;
 3  switch (action.type) {
 4    case "ADD_FAQ_ITEM":
 5      return [
 6        ...state,
 7        {
 8          question: action.question,
 9          answer: action.answer
10        }
11      ];
12    case "EDIT_FAQ_ITEM":
13      faq = [...state];
14      faq[action.index] = {
15        question: action.question,
16        answer: action.answer
17      };
18      return faq;
19    case "DELETE_FAQ_ITEM":
20      faq = [...state];
21      faq.splice(action.index, 1);
22      return faq;
23    default:
24      return state;
25  }
26};
27
28export default faq;

13.5. Combine Multiple Reducers

When our application grows, we will have multiple reducers handling a specific part of the data. We will combine all reducers into one index reducer, such that we can set all reducers in one store. We will create the file reducers/index.js.

1import { combineReducers } from "redux";
2import faq from "./faq";
3
4export default combineReducers({
5  faq
6});