Редукс · Введение
Опубликовано: 2022-03-10В наши дни Redux — одна из самых популярных библиотек для фронтенд-разработки. Однако многие люди не понимают, что это такое и в чем его преимущества.
Как указано в документации, Redux — это контейнер с предсказуемым состоянием для приложений JavaScript. Другими словами, это архитектура потока данных приложения, а не традиционная библиотека или фреймворк вроде Underscore.js и AngularJS.
Дальнейшее чтение на SmashingMag
- Почему вы должны рассмотреть React Native для своего мобильного приложения
- Автоматизация тестирования приложений, игр и мобильного Интернета
- Рендеринг на стороне сервера с помощью React, Node и Express
- Примечания о клиентской доступности
Redux был создан Дэном Абрамовым примерно в июне 2015 года. Он был вдохновлен Flux от Facebook и языком функционального программирования Elm. Redux очень быстро стал популярным благодаря своей простоте , небольшому размеру (всего 2 КБ) и отличной документации. Если вы хотите узнать, как Redux работает внутри, и погрузиться в библиотеку, подумайте о том, чтобы пройти бесплатный курс Дэна.
Redux используется в основном для управления состоянием приложения. Подводя итог, Redux поддерживает состояние всего приложения в одном неизменном дереве состояний (объекте), которое нельзя изменить напрямую. Когда что-то меняется, создается новый объект (используя действия и редукторы). Ниже мы подробно рассмотрим основные концепции.
Чем он отличается от MVC и Flux?
Чтобы дать некоторое представление, давайте возьмем классический шаблон модель-представление-контроллер (MVC), поскольку большинство разработчиков знакомы с ним. В архитектуре MVC существует четкое разделение между данными (моделью), представлением (представлением) и логикой (контроллером). С этим есть одна проблема, особенно в крупномасштабных приложениях: поток данных является двунаправленным. Это означает, что одно изменение (пользовательский ввод или ответ API) может повлиять на состояние приложения во многих местах кода — например, на двустороннюю привязку данных. Это может быть трудно поддерживать и отлаживать.
Flux очень похож на Redux. Основное отличие состоит в том, что Flux имеет несколько хранилищ, которые изменяют состояние приложения, и транслирует эти изменения как события. Компоненты могут подписываться на эти события для синхронизации с текущим состоянием. В Redux нет диспетчера , который во Flux используется для трансляции полезной нагрузки зарегистрированным обратным вызовам. Еще одно отличие Flux в том, что доступно множество разновидностей, что создает некоторую путаницу и непоследовательность.
Преимущества Редукса
Вы можете спросить: «Зачем мне использовать Redux?» Отличный вопрос. Есть несколько преимуществ использования Redux в вашем следующем приложении:
- Предсказуемость результата
Всегда есть один источник правды, хранилище, без путаницы в том, как синхронизировать текущее состояние с действиями и другими частями приложения. - Ремонтопригодность
Наличие предсказуемого результата и строгой структуры облегчает поддержку кода. - Организация
Redux более строго относится к организации кода, что делает его более последовательным и удобным для работы в команде. - Рендеринг сервера
Это очень полезно, особенно для начального рендеринга, для улучшения взаимодействия с пользователем или поисковой оптимизации. Просто передайте магазин, созданный на сервере, на сторону клиента. - Инструменты разработчика
Разработчики могут отслеживать все, что происходит в приложении, в режиме реального времени, от действий до изменений состояния. - Сообщество и экосистема
Это огромный плюс, когда вы изучаете или используете любую библиотеку или фреймворк. Наличие сообщества позади Redux делает его еще более привлекательным в использовании. - Простота тестирования
Первое правило написания тестируемого кода — писать небольшие функции, которые делают только одну вещь и являются независимыми. Код Redux — это в основном функции, которые являются именно такими: маленькими, чистыми и изолированными.
Функциональное программирование
Как уже упоминалось, Redux был построен на основе концепций функционального программирования. Понимание этих концепций очень важно для понимания того, как и почему Redux работает именно так. Давайте рассмотрим основные концепции функционального программирования:
- Он может обращаться с функциями как с объектами первого класса.
- Он может передавать функции в качестве аргументов.
- Он может управлять потоком, используя функции, рекурсии и массивы.
- Он может использовать чистые, рекурсивные, функции высшего порядка, замыкания и анонимные функции.
- Он может использовать вспомогательные функции, такие как карта, фильтрация и уменьшение.
- Он может связывать функции вместе.
- Состояние не меняется (т.е. неизменно).
- Порядок выполнения кода не важен.
Функциональное программирование позволяет нам писать более чистый и модульный код. Написав более мелкие и простые функции, изолированные по объему и логике, мы можем значительно упростить тестирование, сопровождение и отладку кода. Теперь эти меньшие функции становятся повторно используемым кодом , и это позволяет вам писать меньше кода, а меньше кода — это хорошо. Функции можно копировать и вставлять куда угодно без каких-либо изменений. Функции, которые изолированы по области действия и выполняют только одну задачу, будут меньше зависеть от других модулей в приложении, и это меньшее количество взаимосвязей является еще одним преимуществом функционального программирования.

Вы увидите чистые функции, анонимные функции, замыкания, функции высшего порядка и цепочки методов, среди прочего, очень часто при работе с функциональным JavaScript. Redux активно использует чистые функции, поэтому важно понимать, что они из себя представляют.
Чистые функции возвращают новое значение на основе переданных им аргументов. Они не изменяют существующие объекты; вместо этого они возвращают новый. Эти функции не зависят от состояния, из которого они вызываются, и возвращают только один и тот же результат для любого предоставленного аргумента. По этой причине они очень предсказуемы.
Поскольку чистые функции не изменяют никаких значений, они не влияют на область действия или какие-либо наблюдаемые побочные эффекты, а это означает, что разработчик может сосредоточиться только на значениях, которые возвращает чистая функция.
Где можно использовать Redux?
Большинство разработчиков ассоциируют Redux с React, но его можно использовать с любой другой библиотекой представлений. Например, вы можете использовать Redux с AngularJS, Vue.js, Polymer, Ember, Backbone.js и Meteor. Тем не менее, Redux плюс React по-прежнему является наиболее распространенной комбинацией. Обязательно изучайте React в правильном порядке: лучшее руководство — это руководство Пита Ханта, которое очень полезно для разработчиков, которые только начинают работать с React и перегружены всем, что происходит в экосистеме. Усталость от JavaScript вызывает законную озабоченность у разработчиков интерфейса, как новичков, так и опытных, поэтому найдите время, чтобы изучить React или Redux правильно и в правильном порядке.
Одной из причин, по которой Redux так хорош, является его экосистема. Доступно так много статей, учебных пособий, промежуточного программного обеспечения, инструментов и шаблонов. Лично я использую шаблон Дэвида Зуковски, потому что в нем есть все необходимое для создания приложения JavaScript с помощью React, Redux и React Router. Предостережение: старайтесь не использовать шаблоны и стартовые наборы при изучении новых фреймворков, таких как React и Redux. Это сделает его еще более запутанным, потому что вы не поймете, как все работает вместе. Сначала изучите его и создайте очень простое приложение, в идеале в качестве побочного проекта, а затем используйте шаблоны для рабочих приложений, чтобы сэкономить время.
Строительные части Redux
Концепции Redux могут показаться сложными или причудливыми, но они просты. Помните, что библиотека составляет всего 2 КБ. Redux состоит из трех строительных частей: действий, хранилища и редукторов.

Давайте обсудим, что делает каждый.

Действия
Короче говоря, действия — это события. Действия отправляют данные из приложения (взаимодействия с пользователем, внутренние события, такие как вызовы API и отправка форм) в магазин. Магазин получает информацию только из действий. Внутренние действия — это простые объекты JavaScript, которые имеют свойство type
(обычно константное), описывающее тип действия и полезную нагрузку информации, отправляемой в хранилище.
{ type: LOGIN_FORM_SUBMIT, payload: {username: 'alex', password: '123456'} }
Действия создаются с помощью создателей действий. Это звучит очевидно, я знаю. Это просто функции, которые возвращают действия.
function authUser(form) { return { type: LOGIN_FORM_SUBMIT, payload: form } }
Таким образом, вызывать действия в любом месте приложения очень просто. Используйте метод dispatch
, например:
dispatch(authUser(form));
Редукторы
Мы уже обсуждали, что такое редюсер в функциональном JavaScript. Он основан на методе уменьшения массива, где он принимает обратный вызов (редуктор) и позволяет вам получить одно значение из нескольких значений, сумм целых чисел или накопления потоков значений. В Redux редюсеры — это функции (чистые), которые принимают текущее состояние приложения и действие, а затем возвращают новое состояние. Понимание того, как работают редукторы, важно, потому что они выполняют большую часть работы. Вот очень простой редьюсер, который принимает текущее состояние и действие в качестве аргументов, а затем возвращает следующее состояние:
function handleAuth(state, action) { return _.assign({}, state, { auth: action.payload }); }
Для более сложных приложений возможно использование combineReducers()
, предоставляемой Redux (действительно, рекомендуется). Он объединяет все редукторы в приложении в один индексный редуктор. Каждый редьюсер отвечает за свою часть состояния приложения, и параметр состояния у каждого редьюсера разный. combineReducers()
значительно упрощает поддержку файловой структуры.
Если объект (состояние) изменяет только некоторые значения, Redux создает новый объект, значения, которые не изменились, будут ссылаться на старый объект, и будут созданы только новые значения. Это отлично подходит для производительности. Чтобы сделать его еще более эффективным, вы можете добавить Immutable.js.
const rootReducer = combineReducers({ handleAuth: handleAuth, editProfile: editProfile, changePassword: changePassword });
Магазин
Store — это объект, который содержит состояние приложения и предоставляет несколько вспомогательных методов для доступа к состоянию, отправки действий и регистрации слушателей. Весь штат представлен одним магазином. Любое действие возвращает новое состояние через редьюсеры. Это делает Redux очень простым и предсказуемым.
import { createStore } from 'redux'; let store = createStore(rootReducer); let authInfo = {username: 'alex', password: '123456'}; store.dispatch(authUser(authInfo));
Инструменты разработчика, путешествия во времени и горячая перезагрузка
Чтобы упростить работу с Redux, особенно при работе с крупномасштабным приложением, я рекомендую использовать Redux DevTools. Это невероятно полезно, так как показывает изменения состояния с течением времени, изменения в реальном времени, действия и текущее состояние. Это экономит ваше время и усилия, избегая текущего состояния и действий console.log
.

Redux имеет немного другую реализацию путешествий во времени, чем Flux. В Redux вы можете вернуться к предыдущему состоянию и даже изменить свое состояние с этого момента. Redux DevTools поддерживает следующие функции «путешествия во времени» в рабочем процессе Redux (думайте о них как о командах Git для вашего состояния):
- Сброс : сбрасывает состояние, в котором был создан ваш магазин.
- Revert : возвращается к последнему зафиксированному состоянию
- Sweep : удаляет все отключенные действия, которые вы могли запустить по ошибке.
- Commit : делает текущее состояние начальным.
Функция перемещения во времени неэффективна в производственной среде и предназначена только для разработки и отладки. То же самое касается DevTools.
Redux значительно упрощает тестирование, потому что он использует функциональный JavaScript в качестве основы, а небольшие независимые функции легко тестировать. Итак, если вам нужно что-то изменить в дереве состояний, импортируйте только один редюсер, отвечающий за это состояние, и протестируйте его изолированно.
Создайте приложение
В заключение этого вводного руководства давайте создадим очень простое приложение, используя Redux и React. Чтобы всем было легче следовать, я буду придерживаться старого доброго JavaScript, используя как можно меньше ECMAScript 2015 и 2016. Мы продолжим логику входа в систему, начатую ранее в этом посте. В этом примере не используются какие-либо оперативные данные, потому что цель этого приложения — показать, как Redux управляет состоянием очень простого приложения. Мы будем использовать CodePen.
1. Реагировать Компонент
Нам нужны некоторые компоненты и данные React. Давайте создадим простой компонент и отобразим его на странице. Компонент будет иметь поле ввода и кнопку (это очень простая форма входа). Ниже мы добавим текст, представляющий наше состояние:
См. Pen Intro to Redux Алекса Бачука (@abachuk) на CodePen.
2. События и действия
Давайте добавим Redux в проект и обработаем событие onClick
для кнопки. Как только пользователь войдет в систему, мы отправим действие с типом LOGIN
и значением текущего пользователя. Прежде чем мы сможем это сделать, мы должны создать хранилище и передать ему функцию-редуктор в качестве аргумента. На данный момент редьюсер будет просто пустой функцией:
См. Pen Intro to Redux — Шаг 2. События и действия Алекса Бачука (@abachuk) на CodePen.
3. Редукторы
Теперь, когда у нас есть действие, редюсер выполнит это действие и вернет новое состояние. Давайте обработаем действие LOGIN
, возвращающее статус входа в систему, а также добавим действие LOGOUT
, чтобы мы могли использовать его позже. Редуктор auth
принимает два параметра:
- текущее состояние (которое имеет значение по умолчанию),
- Действие.
См. Pen Intro to Redux — Step 3. Reducers от Алекса Бачука (@abachuk) на CodePen.
4. Отображение текущего состояния
Теперь, когда у нас есть начальное состояние (значение по умолчанию в редюсере) и готовый компонент React, давайте посмотрим, как выглядит состояние. Лучшей практикой является передача состояния дочерним компонентам. Поскольку у нас есть только один компонент, давайте передадим состояние приложения как свойство компонентам auth
. Чтобы все работало вместе, мы должны зарегистрировать прослушиватель хранилища с помощью вспомогательного метода subscribe
, ReactDOM.render
в функцию и передав ее в store.subscribe()
:
См. Pen Intro to Redux — Шаг 4. Отображение текущего состояния Алекса Бачука (@abachuk) на CodePen.
5. Войти и выйти
Теперь, когда у нас есть обработчики действий входа и выхода, давайте добавим кнопку выхода из системы и отправим действие LOGOUT
. Последний шаг — выбрать, какая кнопка отображать вход в систему или выход из системы, переместив этот вход за пределы метода рендеринга и отобразив переменную ниже:
См. Pen Intro to Redux — Шаг 5. Вход/выход от Alex Bachuk (@abachuk) на CodePen.
Заключение
Redux набирает обороты с каждым днем. Он успешно используется многими компаниями (Uber, Khan Academy, Twitter) и во многих проектах (Apollo, WordPress' Calypso). Некоторые разработчики могут жаловаться на большие накладные расходы. В большинстве случаев требуется больше кода для выполнения простых действий, таких как нажатия кнопок или простые изменения пользовательского интерфейса. Redux не идеально подходит для всего. Должен быть баланс. Возможно, простые действия и изменения пользовательского интерфейса не обязательно должны быть частью магазина Redux и могут поддерживаться на уровне компонентов.
Несмотря на то, что Redux может быть не идеальным решением для вашего приложения или фреймворка, я настоятельно рекомендую проверить его, особенно для приложений React.
Кредиты изображения на первой странице: Линн Фишер, @lynnandtonic