12. Use Redux To Store Data

12.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 sub components 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 which contains data, a set of reducers which handle (part of) this state, it’s 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 etc. So it’s a unidirectional flow.

12.2. Installing

To install Redux we will run the following command:

$ yarn add redux react-redux

12.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});

12.4. Reducers

Next we will create the reducer by creating the reducers/faq.js file. As stated earlier a reducer is 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;

12.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 so 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});