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

Write the editFaqItem and deleteFaqItem actions.

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

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
5export default faq;

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

 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  }
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";
4export default combineReducers({
5  faq