Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Нормализация данных в Redux React: Redux Toolkit

Большинство приложений работают с данными, которые имеют вложенную структуру. Например, у постов в блоге есть автор и комментарии. У комментариев тоже есть авторы и могут быть лайки.

const blogPosts = [
  {
    id: 'post1',
    author: { username: 'user1', name: 'User 1' },
    body: '......',
    comments: [
      {
        id: 'comment1',
        author: { username: 'user2', name: 'User 2' },
        comment: '.....'
      },
      {
        id: 'comment2',
        author: { username: 'user3', name: 'User 3' },
        comment: '.....'
      }
    ]
  },
];

Работать с такой структурой напрямую тяжело по нескольким причинам:

  • Внутри неё дублируются данные, например, author. Из-за этого усложняется обновление
  • Логика редьюсеров становится тем сложнее, чем больше вложенность

Правильный подход при работе с Redux — воспринимать его как реляционную базу данных. Данные внутри хранилища должны быть нормализованы. При таком взгляде каждый слайс работающий с набором сущностей может восприниматься как отдельная таблица в базе данных.

Основные принципы организации данных в хранилище:

  • Каждая сущность хранится в своём редьюсере.
  • Коллекция сущностей одного типа хранится в виде объекта, где ключи — идентификаторы объектов, а значения — сами объекты.
  • Порядок данных в этом объекте задаётся отдельным массивом состоящим только из идентификаторов.
  • Данные ссылаются друг на друга только по идентификаторам.
{
  posts: {
    entities: {
      post1: {
        id: 'post1',
        author: 'user1',
        body: '......',
        comments: ['comment1', 'comment2'],
      },
      post2: {
        id: 'post2',
        author: 'user2',
        body: '......',
        comments: [],
      },
    },
    ids: ['post1', 'post2'],
  },
  comments: {
    entities: {
      comment1: {
        id: 'comment1',
        author: 'user2',
        comment: '.....',
      },
      comment2: {
        id: 'comment2',
        author: 'user3',
        comment: '.....',
      },
    },
    ids: ['comment1', 'comment2'],
  },
  users: {
    entities: {
      user1: {
        id: 'user1',
        username: 'user1',
        name: 'User 1',
      },
      user2: {
        id: 'user2',
        username: 'user2',
        name: 'User 2',
      },
      user3: {
        id: 'user3',
        username: 'user3',
        name: 'User 3',
      },
    },
    ids: ['user1', 'user2', 'user3'],
  }
}

Теперь данные нормализованы. Каждая сущность хранится в своём собственном редьюсере. Объект entities хранит сами сущности, а ids - идентификаторы. Какие преимущества мы получили?

  • Данные не повторяются, а значит достаточно поменять только одно место при их изменении
  • Редьюсеры не имеют вложенности
  • Данные в таком виде легко извлекать и модифицировать

Теперь посмотрим как это будет выглядеть внутри слайсов:

const slice = createSlice({
  name: 'users',
  initialState: {
    ids: [],
    entities: {},
  },
  reducers: {
    addUser(state, action) {
      const { user } = action.payload;

      state.entities[user.id] = user;
      state.ids.push(user.id);
    }
    removeUser(state, action) {
      const { userId } = action.payload;

      delete state.entities[userId];
      state.ids = state.ids.filter((id) => id !== userId);
    },
    updateUser(state, action) {
      const { userId, data } = action.payload;

      Object.assign(state.entities[userId], data);
    }
  },
});

dispatch(addUser({ user }));
dispatch(removeUser({ userId }));
dispatch(updateUser({ userId, data }));

normalizr

Данные, которые приходят с бекенда, обычно, не нормализованы так как это удобно для фронтенда. Поэтому перед добавлением их в хранилище, сначала нужно выполнить нормализацию. Сделать это можно либо ручным обходом коллекции и преобразованием ее в нужный объект, либо с использованием библиотеки normalizr.


Дополнительные материалы

  1. Нормализация данных в Redux

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
25 мая 10 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»