Использование Redux для управления всем состоянием вашего приложения - это одно. Но убедиться, что структура вашего состояния оптимальна, чтобы ваш код был поддерживаемым и эффективным, - это совершенно новая игра с мячом!

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

Если вы используете React как интерфейсную структуру, скорее всего, вы можете использовать Redux для управления состоянием своего приложения. В этом случае вы реализуете один или несколько редукторов для изменения состояния вашего приложения каждый раз, когда действие отправляется в ответ на действия пользователей. Давайте посмотрим ниже, как перейти от первоначальной неэффективной структуры формы состояния к наиболее эффективной.

Подход формы начального состояния

Предположим, мы пишем приложение, в котором пользователи могут публиковать твиты, и каждый твит имеет комментарии. Предположим также, что твиты могут быть организованы по темам или темам. Базовая и неэффективная форма состояния будет следующей:

Как видите выше, у нас сложная вложенная структура. Такая форма состояния оказывается неэффективной по нескольким причинам:

  • Он глубоко вложен, поэтому изменение состояния для обновления свойства твита требует, чтобы разработчик написал большой объем кода в редукторе.
  • Массив tweets выполняет две функции: он хранит данные (то есть отдельный объект tweet) и упорядочивает твиты, поскольку твиты находятся внутри массива.
  • В этой ситуации массивы неэффективны. Представьте, что у вас в ветке 50 000 твитов. На поиск подходящего твита внутри массива потребуется время. Время поиска внутри массива равно O (n), так как компьютеру необходимо просмотреть весь список элементов, пока не найдет нужный.
  • Обратите внимание, что для примера я даже не включил комментарии, относящиеся к каждому tweet в приведенной выше структуре, так как это было бы еще хуже.

Не используйте массивы для хранения сложных объектов. Как мы увидим позже, единственный смысл использования массивов в нашем состоянии - это упорядочивание элементов. Это потому, что, в отличие от массивов, мы не можем полагаться на объекты для упорядочивания содержащихся в них элементов.

Заменить массивы объектами

Простым и первым улучшением было бы использование объектов вместо массивов. Используя наш предыдущий пример и сосредоточив внимание только на массиве tweets, мы могли бы легко изменить его следующим образом:

Мы изменили предыдущий массив tweets и разделили выполняемую работу на

  1. Создание byId объекта, задача которого - хранить только отдельные твиты
  2. Создание массива allIds, задача которого - сортировать твиты, но здесь мы можем просто указать идентификатор каждого твита вместо всего tweet.

Текущая структура уже намного эффективнее первой. Чтобы найти твит, мы будем искать его по объекту, а не по массиву. Время поиска по объекту - постоянное время, то есть O (1), что является большим улучшением по сравнению с O (n). Кроме того, нас больше не волнует положение каждого твита внутри объекта byId. Массив allIds предназначен для сортировки твитов, и теперь намного проще работать с таким базовым массивом, как allIds.

Включая комментарии к каждому твиту

Не усложняя наш код, теперь мы можем добавлять комментарии, относящиеся к каждому твиту. Один из способов реализации будет следующим:

Такое формирование состояния оказывается намного более эффективным по сравнению с первым примером, который мы использовали. Внутри каждого объекта твита мы ссылаемся только на относящиеся к нему комментарии через массив идентификаторов комментариев. Где-то еще у нас есть объект comments, внутри которого мы можем получить информацию о каждом комментарии.

Теперь у нас есть более «сплющенная» структура, над которой мы можем работать более эффективно. Обновление этой формы состояния потребует небольшого количества кода внутри наших редукторов. Наш код теперь легко поддерживать, и мы уменьшили вероятность ошибки.

Собираем все вместе

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

В отличие от первого подхода, когда мы смешивали массивы и объекты, что затрудняло изменение и поддержку состояния, с этим окончательным подходом теперь легко работать. Наш код легко поддерживать, а наши поисковые операции выполняются очень быстро. Это явно победа!

Давайте рассмотрим несколько ситуаций, чтобы увидеть, что следует делать при изменении некоторых элементов:

Добавить твит

  • Создайте новый объект tweet в объекте byId объекта tweets
  • Добавьте идентификатор нового твита в массив allIds объекта tweets
  • Добавьте идентификатор нового твита в массив tweets внутри соответствующего объекта thread

Редактировать твит

  • Найдите выбранный объект tweet по его идентификатору внутри объекта byId объекта tweets и обновите его

Удалить твит

  • Найдите выбранный объект tweet по его идентификатору внутри объекта byId объекта tweets и удалите его.
  • Удалите идентификатор твита внутри массива allIds объекта tweets
  • Удалите идентификатор твита из массива tweets соответствующего объекта thread.

Добавить комментарий

  • Создайте новый объект comment в объекте byId объекта comments
  • Добавьте идентификатор нового комментария в массив allIds объекта comments
  • Добавьте идентификатор нового комментария в массив comments внутри соответствующего объекта tweet

Редактировать комментарий

  • Найдите выбранный объект comment по его идентификатору внутри объекта byId объекта comments и обновите его.

Селекторы

Один из способов подумать о селекторах - провести параллель с геттером и сеттером. Dispatch похож на сеттер, поскольку он изменяет состояние, в то время как селектор похож на геттер, поскольку он извлекает данные.

Обычно вы будете использовать селекторы в компонентах контейнера при сопоставлении состояния с реквизитами с mapStateToProps. Предположим (как показано в нашем примере), что каждый твит имеет свойство isEditable, которое равно true или false, и что только один твит может быть редактируемым. Если вы хотите получить редактируемый твит, вы можете написать селектор, подобный приведенному ниже:

Я только что привел один пример, но вы можете написать столько селекторов, сколько вам нужно, в зависимости от данных, которые вы хотите получить.

Кроме того, как рекомендовано Дэном Абрамовым, лучше всего записывать свои селекторы в том же файле, что и редуктор. Это имеет смысл, особенно если вы думаете о них как о геттерах / сеттерах. Кроме того, вы также можете обратиться к документации Redux, которая предоставляет подробную информацию.

Удачи в реализации Redux!

Ваше здоровье!