Введение

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

Что такое Redux?

Redux - это контейнер с предсказуемым состоянием для приложений JavaScript.

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

Почему Redux?

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

Что будем строить?

Мы собираемся создать простое приложение, в котором мы сможем управлять двумя объектами: сообщениями и Todos. Посмотреть готовый сайт можно здесь. Мы будем

  • Loading Posts and Todos from the JSON PlaceHolder API
  • Adding a Post or Todo
  • Deleting a Post or Todo

Основные пакеты, которые мы собираемся использовать в этом проекте:

Настройка проекта

  1. Вы можете клонировать проект из этого репо. В главной ветви используются компоненты на основе классов. Если вы любите крючки, просто клонируйте ветку крючков. После клонирования запустите npm install.
  2. Установите Redux Dev Tools как расширение в свой браузер. Redux Dev Tools предоставляет интерфейс для отслеживания изменений вашего состояния, информации о состоянии, действий, позволяет нам вернуться к предыдущим версиям состояния и т. Д.

Понимание Redux Flow

Три основных компонента потока редукции включают:

Магазин. Магазин - это центр данных и логики, на который подписывается ваше приложение.

Действия. Действия - это в основном события, которые «отправляются» из вашего приложения. Действия однозначно идентифицируются по их «типу», и это используется для запуска определенного изменения в данных магазина. Действие - это в основном объект со свойством типа. Мы также можем отправить дополнительные данные в этом объекте редуктору, который будет доступен в параметре действия в функции редуктора.

const action = { type: 'ACTION_TYPE_1' } 
const anotherAction = { type: 'ACTION_TYPE_2', data: 'ANY TYPE OF DATA: OBJECT, STRING, ETC...' }

Редуктор: Редуктор можно рассматривать как прослушиватель событий, который прослушивает действия, а затем обновляет состояние (при необходимости) и возвращает новое и обновленное состояние. Редуктор - это функция, которая принимает старое состояние и объект действия и возвращает обновленное / новое состояние.

const reducer = (prevState, action) => { 
   /* STUFF HAPPENS */ 
   return updatedState 
}

Redux Flow начинается с действия определенного «типа», отправляемого из пользовательского интерфейса приложения из-за некоторого события. Действие выполняется редуктором, а затем редуктор изменяет состояние в соответствии с «типом» действия. Это может изменить только определенную часть состояния. Остальные данные воссоздаются и сохраняются.

На приведенной выше диаграмме в блоке Корневой редуктор есть два небольших блока Reducer. Это связано с тем, что у магазина может быть несколько фрагментов / частей состояния. Каждый фрагмент состояния имеет свой собственный список действий и отдельный редуктор. Однако важно отметить, что Магазин может принимать только один Редуктор, то есть Корневой Редуктор.
Таким образом, отдельные фрагменты объединяются в корневой редуктор, и отдельные фрагменты становятся доступными путем сопоставления их с объектом, как мы увидим позже.

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

Redux Store не может самостоятельно выполнять асинхронные задачи. Все операции происходят синхронно. Но почти все реальные приложения должны выполнять асинхронные задачи.

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

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

Прохождение кода

Взгляните на папку src, которую мы видим

Всего 4 компонента:

  • Сообщения - отображение всех сообщений, сообщений о загрузке и ошибках. Отображает список компонентов публикации.
  • Todos - отображает все Todos, сообщения о загрузке и ошибках. Отображает список компонентов Todo.
  • Todo - отображает одно задание
  • Сообщение - отображает отдельное сообщение

Контейнер Main - это родительский компонент, который отображает как компоненты «Сообщения», так и компоненты Todos.

Давайте сначала пройдемся по файлам в папке магазина.

store / index.js

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

Также импортируем rootReducer из папки redurs.

Затем мы настраиваем Redux Dev Tools. (Для получения дополнительной информации о подключении Redux Dev Tools проверьте здесь)

Двигаясь дальше, теперь мы используем метод createStore для создания хранилища и передачи rootReducer и использования add thunk в качестве промежуточного программного обеспечения с помощью функции applyMiddleware. .

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

const composeEnhancers = process.env.NODE_ENV === 'development' ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose : compose;

store / types.js

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

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

Я собираюсь объяснить одну часть (Посты) штата. Те же концепции и для другого фрагмента (Todo).

actions / post-actions.js

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

Пример функции, которая напрямую возвращает объект действия:

Первая функция просто возвращает объект действия. Вторая функция просто возвращает объект с некоторыми дополнительными данными, полученными через параметры.

Пример функции, возвращающей преобразователь:

Эта функция возвращает другую функцию (в основном преобразователь), которая имеет один параметр, dispatch, который будет использоваться для отправки событий до и / или после завершения асинхронных задач.
Как видно из кода, в начале этой функции мы отправляем действие LOADING_POSTS, вызывая функцию loadPostsStart.
После успешного получения сообщений выполняется действие SET_POSTS путем вызова функции setPosts и передачи выбранных сообщений в качестве параметра. Наконец, если возникает ошибка, мы отправляем действие POST_ERROR, вызывая функцию setError.

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

Вот еще один преобразователь, использующий параметры.

действия / index.js

В этом файле все действия из разных файлов импортируются и экспортируются в один объект, который будет использоваться в компонентах React для отправки действий.

reducer / post-reducer.js

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

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

Глубокое клонирование действительно важно, если вы работаете с массивами, вложенными объектами или массивами объектов, и вы будете работать с ними довольно часто.

Лучший и самый простой способ выполнить глубокое клонирование всего этого - использовать JSON.parse () и JSON.stringify ().

Вот действие, в котором мы обновляем сообщения, представляющие собой массив объектов.

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

Вы можете просматривать комментарии в файлах редуктора на каждом этапе.

redurs / index.js

В этом файле мы объединяем все редукторы в один редуктор, широко известный как rootReducer. Обратите внимание, когда мы вызываемcommonReducers, мы сопоставляем каждый редуктор (который относится к определенной части состояния) со свойством объекта. Это используется для различения различных частей состояния в приложении React.

Подключение магазина к приложению React

Теперь последний шаг - подключить магазин к нашему приложению React.

Шаг 1. Поставщик в src / index.js

Мы импортируем компонент Provider и хранилище и передаем его в хранилище props. Все приложение обернуто компонентом Provider.

Шаг 2. mapStateToProps и mapDispatchToProps

Нам нужно создать две константы -

  1. mapStateToProps - функция с одним параметром, состоянием, которое можно использовать для извлечения данных из разных фрагментов состояния и сопоставления их со свойством, которое будет доступно в компоненте в качестве опоры.
    Например: сообщения, loadingPosts (извлеченные из фрагмента сообщений), задач (извлеченных из фрагмента задач) и т. д. можно получить в виде props.posts, props.todos и т. д.
  2. mapDispatchToProps - функция с отправкой одного параметра, которая используется для сопоставления функций, вызывающих функцию отправки, с необязательными дополнительными данными для отправки определенного события. Они также доступны как реквизиты в подключенном компоненте.

Наконец, мы вызываем connect, передавая объекты mapStateToProps и mapDispatchToProps, а затем наш компонент. И затем мы обычно используем их в качестве реквизита в наших приложениях.

Вы можете вызвать connect либо с помощью mapStateToProps (опуская второй аргумент), либо с помощью mapDispatchToProps (передав null в качестве первого аргумента).

Использование Redux DevTools

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

Ну это все. Надеюсь, у вас есть твердое базовое представление о том, как Redux работает вместе с React. Поиграйте с кодом. Вы всегда можете узнать больше в Официальной документации. Не стесняйтесь подавать любые запросы на слияние. Будем рады их видеть. До скорого. 👋❤

Еще мои статьи:

Первоначально опубликовано на https://dev.to 29 ноября 2020 г.