Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. React
Code

Начало работы с Redux: учимся на примере

by
Difficulty:IntermediateLength:MediumLanguages:

Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)

Redux помогает вам управлять состоянием, устанавливая состояние на глобальном уровне. В предыдущем уроке мы подробно рассмотрели архитектуру Redux и ее неотъемлемые компоненты, такие как действия, создатели действий, хранилище и редукторы.

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

Тем не менее, это нормально, если вы не читали первый пост - вы все равно сможете следить, пока вы знакомы с основами Redux. Код для учебника доступен в репозитории, и вы можете использовать его в качестве отправной точки.

Создание списка контактов с помощью Redux

Мы собираемся создать базовый список контактов со следующими функциями:

  • показать все контакты
  • поиск контактов
  • получить все контакты с сервера
  • добавить новый контакт
  • отправить новые контактные данные на сервер

Вот как будет выглядеть наше приложение:

Getting Started With Redux Final View of the Contact List
Конечный продукт - Список контактов


Getting Started With Redux Final View of the Contact Form
Конечный продукт - Добавить контакт

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

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

Создаем эскиз дерева состояний

Вы можете скачать демо-приложение Reaction-redux из моего репозитория GitHub. Клонируйте репо и используйте ветку v1 в качестве отправной точки. Ветвь v1 очень похожа на шаблон create-react-app. Разница лишь в том, что я добавил несколько пустых каталогов для организации Redux. Вот структура каталогов.

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

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

Наше хранилище должно иметь два свойства - contacts ты и ui. Свойство contacts заботится обо всех состояниях, связанных с контактами, тогда как ui обрабатывает специфическое для интерфейса состояние. В Redux нет жесткого правила, которое не позволяет вам размещать объект ui в качестве подсостояния contacts. Не стесняйтесь организовать свое состояние таким образом, чтобы оно имело смысл для вашего приложения.

Свойство contacts имеет два вложенных свойства: contactlist и newContact. contactlist представляет собой массив контактов, в то время как newContact временно сохраняет контактные данные во время заполнения формы контакта. Я собираюсь использовать это как отправную точку для создания нашего замечательного приложения со списком контактов.

Как организовать Redux

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

Самым распространенным шаблоном, который вы найдете, является структура файлов и папок в стиле Rails. У вас будет несколько каталогов верхнего уровня, подобных приведенным ниже:

  • components: место для хранения немых компонентов React. Этим компонентам все равно, используете ли вы Redux или нет.
  • containers: каталог для компонентов Smart React, которые отправляют действия в хранилище Redux. Здесь будет происходить связь между redux и react.
  • actions: создатели действий перейдут в этот каталог.
  • reducers: каждый редуктор получает отдельный файл, и вы разместите всю логику редуктора в этом каталоге.
  • store: логика для инициализации состояния и настройки хранилища будет здесь.

Изображение ниже демонстрирует, как может выглядеть наше приложение, если мы будем следовать этому шаблону:

Organising Folder structure in Redux

Стиль Rails должен работать для небольших и средних приложений. Однако, когда ваше приложение развивается, вы можете рассмотреть возможность перехода к подходу в стиле домена или другим популярным альтернативам, которые тесно связаны со стилем домена. Здесь каждая функция будет иметь собственный каталог, и все, что связано с этой функцией (доменом), будет находиться внутри нее. На рисунке ниже сравниваются два подхода: стиль Rails слева и стиль домена справа.

Comparison of two popular techniques for organising Redux and React

А пока давайте создадим каталоги для components, containers, store, reducers и action. Начнем со store.

Одно хранилище, несколько редукторов

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

У оператора switch есть три случая, которые соответствуют трем действиям, которые мы будем создавать. Вот краткое объяснение того, для чего предназначены действия.

  • HANDLE_INPUT_CHANGE: Это действие запускается, когда пользователь вводит новые значения в форму контакта.
  • ADD_NEW_CONTACT: это действие отправляется, когда пользователь отправляет форму.
  • TOGGLE_CONTACT_FORM: это действие пользовательского интерфейса, которое позволяет показать/скрыть контактную форму.

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

  1. Мы используем один редуктор. Хотя пока что звучит один редуктор, представьте, что вся ваша бизнес-логика под одним очень большим редуктором.
  2. Приведенный выше код не соответствует структуре Redux, которую мы обсуждали в предыдущем разделе.

Чтобы устранить проблему с одним редуктором, в Redux есть метод combReducers, который позволяет создавать несколько редукторов, а затем объединять их в одну редукционную функцию. Функция combReducers улучшает читаемость. Поэтому я собираюсь разделить редуктор на две части: contactsReducer и uiReducer.

В приведенном выше примере createStore принимает необязательный второй аргумент, который является начальным состоянием. Однако, если мы собираемся разделить редукторы, мы можем переместить весь initialState в новое местоположение файла, скажем, redurs / initialState.js. Затем мы импортируем подмножество initialState в каждый файл редуктора.

Расщепление редуктора

Давайте реструктурируем наш код, чтобы исправить обе проблемы. Сначала создайте новый файл с именем store/createStore.js и добавьте следующий код:

Затем создайте корневой редуктор в reducers/index.js следующим образом:

Наконец, нам нужно создать код для contactsReducer и uiReducer.

reducers/contactsReducer.js

reducers/uiReducer.js

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

Поскольку мы рассмотрели много кода, давайте посмотрим на изменения, которые мы внесли в наш подход:

  1. Был введен вызов combineReducers, чтобы связать редукторы.
  2. Состояние объекта ui будет обрабатываться uiReducer, а состояние контактов - contactReducer.
  3. Для поддержания чистоты редукторов были использованы операторы спреда. Синтаксис из трех точек является частью оператора распространения. Если вас не устраивает такой синтаксис, вам следует рассмотреть возможность использования библиотеки, такой как Immutability.js.
  4. Начальное значение больше не указывается в качестве необязательного аргумента для createStore. Вместо этого мы создали для него отдельный файл с именем initialState.js. Мы импортируем initialState и затем устанавливаем состояние по умолчанию, выполняя state=initialState.ui.

Инициализация состояния

Вот код для файла reducers/initialState.js.

Действия и создатели действий

Давайте добавим пару действий и создателей действий для добавления обработки форм, добавления нового контакта и переключения состояния пользовательского интерфейса. Если вы помните, создатели действий - это просто функции, которые возвращают действие. Добавьте следующий код в action/index.js.

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

В нашем случае мы создали три действия.

TOGGLE_CONTACT_FORM не нуждается в полезной нагрузке, потому что каждый раз, когда действие запускается, значение ui.isContactFormHidden переключается. Булевозначные действия не требуют полезной нагрузки.

Действие HANDLE_INPUT_CHANGE запускается при изменении значения формы. Так, например, представьте, что пользователь заполняет поле электронной почты. Затем действие получает "email" и "bob@example.com" в качестве входных данных, а полезная нагрузка, передаваемая редуктору, представляет собой объект, который выглядит следующим образом:

Редуктор использует эту информацию для обновления соответствующих свойств состояния newContact.

Рассылка действий и подписка на хранилище

Следующим логическим шагом является отправка действий. Как только действия отправляются, состояние изменяется в ответ на это. Для отправки действий и получения обновленного дерева состояний Redux предлагает определенные действия хранилища:

  • dispatch(action): отправляет действие, которое потенциально может вызвать изменение состояния.
  • getState(): возвращает текущее дерево состояний вашего приложения.
  • subscriber(listener): слушатель изменений, который вызывается каждый раз, когда отправляется действие и изменяется некоторая часть дерева состояний.

Перейдите в файл index.js и импортируйте функцию configureStore и три действия, которые мы создали ранее:

Затем создайте объект store и добавьте прослушиватель, который регистрирует дерево состояний каждый раз при отправке действия:

Наконец, отправьте несколько действий:

Если все работает правильно, вы должны увидеть это в консоли разработчика.

Redux store being logged in developer console

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

Заключение

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

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

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.