Register to get access to free programming courses with interactive exercises

Reducers JS: Redux (React)

We call a state everything that we store. But not all states are equally helpful. Here's the classification introduced by the Redux documentation:

  • Domain data – application data that needs to be displayed, used, and modified. For example, a list of users downloaded from the server
  • App state – data that determines the application's behavior. For example, the currently open URL
  • UI state – data that determines how the UI looks, like displaying a list in the tile view

The store is the application's core, so we should describe the data inside it in terms of domain data and app state rather than as a tree of UI components. For example, we should not generate a state like state.leftPane.todoList.todos. It's rare for a component tree to reflect directly on a state structure, and that's okay. The view depends on the data, not the other way around.

A typical state structure looks like this:

{
    domainData1 : {}, // Todos
    domainData2 : {}, // Comments
    appState1 : {},
    appState2 : {},
    uiState1 : {},
    uiState2 : {},
}

You can find more details about working with UI states in the corresponding lesson.

We mentioned in the JS: React course that the state structure should resemble a database. Everything should be as flat and normalized as possible:

{
  todos: [
    { id: 1, name: 'why?' },
    { id: 3, name: 'who?' },
  ],
  comments: [
    { id: 23, todoId: 3, text: 'great!' },
  ],
}

With this structure, it's easy to write a reaction to actions, update, add, and delete data. There's a little nesting, so everything is nice and clear.

But there is one other problem which we'll always have to deal with. As the number of entities grows, the reducer gets quite hefty. It becomes a giant piece of code that does everything. To solve this problem, Redux has a built-in mechanism. It allows you to create multiple reducers and combine them.

It works like this: each top-level property gets its reducer, then we combine them into a root reducer using the combineReducers() function. Then we use it to create the store:

import { combineReducers, createStore } from 'redux';

const todosReducer = (state = [], action) => {
  // data from todos will go here
};

const commentsReducer = (state = [], action) => {
  // data from comments will go here
};

const rootReducer = combineReducers({
  todos: todosReducer,
  comments: commentsReducer,
});
const store = createStore(rootReducer);

// If we call reducers as properties in the state, we can shorten the code:
// const todos = (state = [], action) => { ... };
// const comments = (state = [], action) => { ... };
// const rootReducer = combineReducers({ todos, comments });

The state comes to each reducer, but not the store's entire state, only the part in the corresponding property. Make sure to keep this in mind.

Redux Reducer Combination

Reducers can even be nested without any special tools. They are ordinary functions that take data as input and return new data. If you use this approach, you will find a feature that seems frightening at first glance. Since each reducer has access only to its part of the state, actions that cause changes in several places at once will be in different reducers:

const todos = (state = {}, action) => {
  switch (action.type) {
    case 'TODO_REMOVE':
      // ...
  }
};

const comments = (state = {}, action) => {
  switch (action.type) {
    // When deleting a ToDo, make sure to remove all of its comments
    case 'TODO_REMOVE':
      // ...
  }
};

In other words, we should repeat the part of the case in the necessary reducers rather than try to get the missing parts of the state.


Recommended materials

  1. Normalizing state shape

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

Bookmate
Health Samurai
Dualboot
ABBYY
Suggested learning programs
profession
Development of front-end components for web applications
10 months
from scratch
Start at any time

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.