Введение в Redux и как обновляется состояние в приложении Redux

Что такое Redux?

Redux — это библиотека с открытым исходным кодом для улучшения предсказуемости состояния в приложении JavaScript. Это независимая библиотека, обычно используется с другими библиотеками, такими как React и Angular, для лучшего управления состоянием приложения. Redux был создан Дэном Абрамовым в 2015 году для эффективного управления сложным состоянием.

Когда приложение становится больше, становится сложнее управлять состоянием и отлаживать проблемы. Это становится проблемой, чтобы отследить, когда и где состояние изменяется и где изменения должны быть отражены. Иногда пользовательский ввод вызывает некоторый вызов API, который обновляет некоторую модель. Эта модель, в свою очередь, обновляет некоторое состояние или, может быть, другую модель и так далее.

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

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

Как мы уже говорили ранее, основная цель Redux — обеспечить предсказуемое управление состоянием в наших приложениях. Redux достигает этого, имея единый источник правды, то есть единое дерево состояний (State Tree). State Tree — это простой объект JavaScript, который содержит все состояние нашего приложения. Есть только несколько способов взаимодействия с state. И это облегчает нам отладку или отслеживание нашего состояния.

Теперь у нас есть только одно основное состояние, которое включает все состояния приложения, расположенного в одном месте. Любые изменения, внесенные в State Tree, отражаются во всем приложении, поскольку это единственный источник данных для приложения. И это первый фундаментальный принцип Redux.

Состояние всего вашего приложения хранится в дереве объектов в одном хранилище.

Способы взаимодействия с State Tree:

  • Получение состояния
  • Прослушивание изменений в state
  • Обновление состояния

Store представляет собой единый блок , который удерживает состояние дерева и методы для взаимодействия с деревом состояний. Нет другого способа взаимодействия с состоянием внутри хранилища, кроме как с помощью данных методов.

Давайте поговорим о методах, которые store дает нам для взаимодействия с state.

  • getState() — возвращает текущее состояние приложения.
  • dispatch(action) — Единственный способ обновить состояние — это отправить действие и выполнить его с помощью dispatch(action).
  • subscribe(listener) — целью этого метода является прослушивание изменений состояния. Каждый раз, когда состояние изменяется, оно вызывается и возвращает обновленное состояние.
  • replaceReducer(nextReducer) — заменяет reducer, используемый в данный момент хранилищем для вычисления состояния.

Библиотека была создана в 2015 году Даниилом Абрамовым и Эндрю Кларком. Первую версию Абрамов создал во время подготовки к конференции React Europe. По словам Абрамова, он пытался создать реализацию идеи Flux с другой логикой. Абрамов был потрясён сходством между редьюсерами и Flux, так что он попытался совместить их.

Абрамов обратился к Кларку (создателю Flummox, одной из реализаций Flux), и совместно они разработали Redux. Как утверждает Абрамов, именно благодаря Кларку был реализован комплекс экосистемных средств, логичный API, а также точки расширения, такие как связующее программное обеспечение и усилители хранилища.

Принципе работы Redux

Теперь разберём основные принципы работы с Redux, для наглядности я покажу вам такую схему:

Давайте внимательно посмотрим на схему и разберём что к чему у неё твориться, в начале мы вызываем Actions, например при нажатие кнопки.

Он в свою очередь отправляется в Reducer, он выполняет какое то действие и потом обновляет Store который содержит State, его выводим в интерфейс.

То есть если кратко говоря, то мы обновили State отправив Actions в Reducer, вот список что и для чего:

  • Action — Действие;
  • Reducer — Функция для изменения состояния;
  • Store — Главный объект который в себе всё содержит;
  • State — Состояние или данные;

Теперь перейдём к работе с этой библиотеки, покажу вам не большой пример из официальной документации, ссылка ниже.

Сначала сделаем редюсер:

JavaScript

123456789101112 // Создание РедюсераfunctioncounterReducer(state={value:0},action){  // Выбор типа action   switch(action.type){    case’counter/incremented’:      return{value:state.value+1}    case’counter/decremented’:      return{value:state.value-1}    default:      returnstate  }}

Давайте разберём из чего состоит редюсер, первое мы в него передаём базовое состояние и action, внутри же мы используем оператор switch который проверяет чему равен action.type, который в себе хранит тип действия виде обычной строки.

После того как проверит и зависимо от действия вернёт новое состояние state, если действия нет, то вернёт тикушие состояние.

Теперь нам нужно создать Store, делается это через функцию createStore(), в качестве параметра она принимает редюсер:

JavaScript

1 let store=createStore(counterReducer)

Теперь можем делать какие то действия, сам store в себе хранит три метода, вот они:

  • subscribe() — Используется при изменение state;
  • getState() — Получает State;
  • dispatch() — Вызывает Action;

Давайте теперь рассмотрим полноценную работу со всем этим, вот не большой код:

JavaScript

123456789 // Проверка измененийstore.subscribe(()=>console.log(store.getState())) // Делаем инкрементstore.dispatch({type:’counter/incremented’})// Делаем инкрементstore.dispatch({type:’counter/incremented’})// Делаем декрементstore.dispatch({type:’counter/decremented’})

В начале мы запустили subscribe() которая будет выводить в консоль браузера состояние когда он измениться, потом вызываем три раза dispatch(), сначала инкремент, потом один раз декремент, и того конечный результат будет {value: 0}.

В целом как видите всё очень просто, но ещё стоит упомянуть в action параметр payload, дело в том, что вам иногда надо будет передать какие либо данные для state, и для этого в объекте action используете этот параметр.

Вот вам не большой пример кода используя его:

JavaScript

12345678910 functioncounterReducer(state={value:0},action){  switch(action.type){    case’counter/plus’:      return{value:state.value+action.payload}    case’counter/minus’:      return{value:state.value-action.payload}    default:      returnstate  }}

Как видите мы тут изменили редюсер, теперь к state мы будем добавлять не просто единицу а какое то число, но теперь мы для action для удобства мы сделаем функцию, которая будет возвращать объект с type и payload.

Вот пример этого:

JavaScript

123456 constcounterPlus=(n)=>{    return{        type:’counter/plus’,        payload:n    }}

То есть мы payload назначаем из параметра который передали в функцию, теперь её можем передать в dispatch(), примерно так:

JavaScript

1 store.dispatch(counterPlus(22))

Для старта и чтобы делать простые задачи с Redux, вам этого хватит.

Когда и зачем нужен

Здравый смысл подсказывает, что нет смысла при каждом новом проекте постоянно запускать новые фреймворки и работать только в них, ведь их описывают как самые новые и блестящие инструменты для самых разных задач. Но разве компоненты не имеют своего состояния? Зачем вообще нужен этот вот самый инструмент для управления данным состоянием некоторого компонента?

Не поймите превратно, React велик и могуч и вполне можно в проекте обойтись только одним этим фреймворком и более ничего не использовать. Тем более, что мы уже рассматривали подробно React и приводили примеры веб-проектов, что использовали только эту библиотеку для создания функционала интерфейса (то же самое приложение, по сути). Но по мере того, как приложение становится более сложным, с большим количеством разных компонентов, использование всего лишь одного фреймворка для управления всем этим «массивом», объемом данных и так далее может стать очень проблематичным и осложненным действом. Проблем может появиться много, даже неудобств и излишней трудоёмкости.

И именно в этот момент Redux способен сэкономить время; он значительно уменьшает и упрощает сложности, возникающие в таких больших приложениях. Если у веб-разработчика есть опыт работы в React, он может великолепно понять, что поток данных React таков, что родительские компоненты передают props (входные параметры) дочерним компонентам. В огромном приложении с данными, что используются в разных компонентах, постоянно изменяемыми и сохраняемыми в хранилище, создающими множественные связи – рано или поздно сам код станет очень трудно читать и даже улучшать. Вам самим, в первую очередь.

Чтобы представлять, о чем идет речь, посмотрим на диаграмму ниже.

В React (как, впрочем, и в других фреймворках) связь между двумя компонентами, не имеющими отношения родитель-потомок (дочерний элемент), не рекомендуется. React обращает внимание, что если такое сделать (создать связь), можно вполне создать собственную глобальную систему событий по шаблону Flux; и именно в этот момент и появляется на сцене Redux.

С Redux у нас есть хранилище, в котором можно сохранять все состояния приложения. Если в компоненте A происходит изменение состояния, оно затем передается в хранилище, а другие компоненты B и C, которые должны знать об этом изменении состояния в компоненте A, могут получать эту самую информацию об этом изменении из хранилища:

Увидели? Это даже намного лучше, чем мы предполагали. Если бы наши компоненты взаимодействовали друг с другом, мы создали бы уязвимую и нечитаемую базу программного кода с множеством ошибок. Redux делает ситуацию другой, меняет её и совершенствует.

Компонент A отправляет изменения своего состояния в хранилище, и если Компонент B и C нуждаются в данных об этих изменениях состояния, они могут получить их из хранилища. Таким образом, логика потока данных является бесшовной.

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

  • Предсказуемость результатов

Имея только один источник данных (хранилище), у разработчиков становится мало проблем с синхронизацией текущего состояния компонентов (данных этого самого хранилища) с действиями и другими частями приложения.

  • Поддержание работоспособности

Redux имеет строгие рекомендации о том, как должен быть организован код. Соответственно и, что разумно, это дополнительно обеспечивает предсказуемый результат, который упрощает управление кодом.

  • Простота тестирования

Работа с кодом в Redux включает в себя чистые функции, которые изолированы друг от друга, что коррелирует с золотым правилом написания тестируемого кода: написать небольшие функции, которые делают только что-то одно и являются независимыми.

Когда Redux может не потребоваться

Это может показаться некоторым читателям вполне очевидным, но мы  все равно упомянем об этом. Не обязательно использовать Redux. Иногда имеет смысл и вовсе не делать этого. Если какой-либо из сценариев ниже верен для вас, вам, вероятно, вообще не нужен Redux:

  • Вы и ваши друзья (или коллеги) уже получили заранее определенный способ совместного использования и организации состояния между компонентам. Иными словами, вам уже было сказано в каком фреймворке нужно доделать/переделать/создать.
  • Вы все еще обучаетесь работать в React или любом ином фреймворке. Redux необычен и без знания, как минимум, того же React новичкам может быть сложновато.
  • Если приложение будет состоять в основном из простых действий, таких как изменения пользовательского интерфейса,  то они вполне могут и не быть частью хранилища Redux. Обработать их можно на уровне компонентов.
  • Вам не нужно управлять событиями на стороне сервера (SSE) или группой веб-сайтов, что будут использовать одинаковые компоненты, но с изменяемым состоянием.
  • Если планируется создать выборку данных из одного источника данных для каждого представления.

Нашли что-то свое, тогда с большой вероятностью Redux может не потребоваться. И неважно, какое приложение, какая работа сайта и какой проект. Все зависит от их сложности, масштабности. Но что касается самого Redux, то этот фреймворк при своем весе около 2 КБ имеет весьма непростые возможности.

Функциональное программирование и Redux

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

Так что же это за принципы такие «функционального программирования»?

  • Могут использоваться «чистые», первого класса.
  • Могут использоваться вспомогательные функции (высшего порядка), такие как карта (map), фильтр (filter).
  • Функции могут связываться вместе, рассматриваться, как объекты первого класса, передаваться в качестве аргументов.
  • Существует возможность управления потоком данных и объектов, используя функции и массивы.
  • Порядок выполнения кода неважен

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

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

Обновление состояния в приложении

Единственный способ обновить состояние — отправить action. Это второе правило.

Action — это простой объект JavaScript, который отслеживает конкретное событие, происходящее в приложении. Что делает его особенным, так это свойство type, которое является его необходимой частью.

Основная цель этого свойства — сообщить Redux о происходящем. Этот тип должен описывать action. Наряду со свойством type у него может быть другая информация о происходящем событии.

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

Здесь у нас есть action, чтобы добавить книгу в корзину.

Как только мы определим наш action, мы передадим его диспетчеру. store.dispatch() — это функция, предоставляемая библиотекой, которая принимает действие для выполнения action и изменения состояния. Redux ограничивает обновление состояния только этим методом.

Этот строгий способ обновления состояния гарантирует, что состояние не может быть изменено напрямую ни во view, ни любым сетевым обратным вызовом. Единственный способ обновить состояние — определить action и затем отправить его. Помните, что action — это простые объекты JavaScript. Action могут быть зарегистрированы, сериализованы и воспроизведены для целей отладки.

Теперь у нас есть store, state и action в нашем приложении для выполнения некоторых задач. Теперь нам нужен способ использовать эти action для обновления. Это можно сделать с помощью чистой функции, и это правило № 3.

Нам нужна простая чистая функция, которая в качестве параметра принимает текущее state приложения и action, которое нужно выполнить с состоянием, а затем возвращает обновленное состояние. Эти функции называются reducer.

Они называются reducer, потому что они принимают коллекцию значений, переводят ее в обновленное состояние и затем возвращают. Поскольку reducer являются чистыми функциями, они не изменяют исходное состояние. Вместо этого они возвращают обновленное состояние в новом объекте. Наше приложение может иметь один или несколько reducer. Каждый reducer может иметь соответствующее action для выполнения определенных задач.

Поскольку reducer являются чистыми функциями, они должны иметь следующие атрибуты:

  • При одинаковом вводе он должен возвращать один и тот же вывод каждый раз — мутация не допускается.
  • Никаких побочных эффектов — Нет изменений данных вызовов API из внешнего источника.Если мы соединяем точки, Redux — это библиотека, в которой есть хранилище, содержащее дерево состояний и несколько методов взаимодействия с состоянием. Единственный способ обновить состояние внутри хранилища — это отправить action и определить функцию reducer для выполнения задач на основе заданных действий. После отправки action переходит в функции reducer, который выполняет задачи и возвращает обновленное состояние в хранилище. Вот что такое Redux.

Как установить Redux

Теперь перейдём к установки Redux, установить его можно только через NPM:

PowerShell

1 npm install—save redux

Больше вы не как не установите его, также у вас должен быть bubel.

Различие между React context и React-Redux

React context предоставляет способ направлять данные через дерево компонентов без необходимости передачи свойств сверху вниз вручную на каждом уровне.

Используется для небольших приложений, тогда как Redux сам по себе обеспечивает более основательное и мощное управление состояниями.

React-Redux — это официальная библиотека, которая предоставляет привязки React для Redux. Она позволяет компонентам React считывать данные из хранилища Redux и отправлять туда действия для обновления данных.

Итоги

Давайте подведем итог тому, что мы тут узнали, чтобы подвести итоги.

  • Redux  - контейнер с предсказуемым состоянием с открытым исходным кодом
  • State Tree (дерево состояний) — простой объект JavaScript, который содержит состояние всего приложения
  • Три способа взаимодействия со state:
    Store  - единый блок , который содержит состояние дерева и методы для взаимодействия с деревом состояний
    Action  - Javascript объект для описания действий
    Reducers  - чистая Javascript функция принимающая текущее состояние и действие, чтобы вернуть новое состояние

Поскольку Redux является независимой библиотекой, которую можно использовать с React, Angular или любой другой библиотекой, я избегал создания примера приложения с любой из этих библиотек представлений. Вместо этого я сосредоточился только на основных концепциях Redux.

Источники
  • https://dev-gang.ru/article/vvedenie-v-redux-i-kak-obnovljaetsja-sostojanie-v-prilozhenii-redux-7h24vgtrkr/
  • https://prognote.ru/web-dev/front-end/redux-basics/
  • https://wayup.in/blog/when-and-why-redux-can-be-useful
  • https://nuancesprog.ru/p/7778/

tett
Зарплатто.ру - сайт о зарплатах и доходах, деньгах и финансах