Мы посвятим всю эту главу Redux

Мы посвятим эту главу Redux.

Вот часть I этого урока.

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

Почему Redux так важен? Хороший вопрос!

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

Мы позволим Redux управлять state нашего приложения, а React - пользовательским интерфейсом представления (пользовательским интерфейсом). Он отделяет state ответственности от React.

Как это работает? Я покажу тебе.

Установка

Во-первых, давайте установим две зависимости.

  • redux:
    Самая библиотека Redux, которая содержит все функции.
  • react-redux:
    клей для React и Redux.

Большой! Теперь нам нужно подключить приложение React к Redux. Мы импортируем Provider из react-redux и заключим наше приложение в тег Provider.

Создание магазина

Что такое магазин? Магазин - это большая часть терминологии Redux. Магазин - это большой объект {}, который хранит состояние нашего приложения. В магазине собраны наши actions и reducers.

Из документов:

У магазина есть следующие обязанности

  • Сохраняет состояние приложения.
  • Разрешает доступ к состоянию через getState().
  • Позволяет обновлять состояние через dispatch(action).
  • Регистрирует слушателей через subscribe(listener).
  • Обрабатывает отмену регистрации слушателей с помощью функции, возвращаемой subscribe(listener).

Provider ожидает ровно одну опору - свойство store.

createStore

Давайте создадим наш Store.js внутри src/ с помощью следующего кода.

Мы импортируем метод createStore из redux и передаем наш rootReducer в качестве аргумента.

Затем мы импортируем его в наш src/index.js файл и добавляем опору в тег Provider.

Затем мы импортируем Store и передаем его Provider в качестве опоры.

Если мы заглянем внутрь браузера, мы увидим большую красную ошибку. Это совершенно нормально - мы еще не сделали rootReducer.

Редукторы

Что такое редукторы?

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

  1. action type под названием "BUTTON_CLICKED" запускает action с полезной нагрузкой. action возвращает простой объект.
  2. Все reducers будут вызваны. reducer с типом "BUTTON_CLICKED" будет дополнительно вызван для возврата нового state. Полезная нагрузка передается action. Все редукторы по умолчанию возвращают state.
  3. store отслеживает любые изменения в reducers и сохраняет новые state.
  4. store передает новое state в наши представления React.
  5. React обновляет представление.

Много жаргона - легче понять его в действии.

Мы создали store (№3), а теперь переходим к reducers (№2).

Вы можете спросить: «Все ли это необходимо?»

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

Доделать редукторы? Нашему store они нужны.

Мы собираемся создать специальный каталог для редукторов под названием src/reducers. Внутри каталога reducers мы создаем файл index.js.

Внутри src/reducers/index.js мы импортируем combineReducers из Redux. combineReducers объединяет все наши редукторы в один редуктор.

Зачем нужен только один редуктор? Аналог Store принимает в качестве аргумента только один редуктор rootReducer.

Теперь у нас есть константа с именем rootReducer, которую мы экспортируем.

Store принимает только что экспортированный rootReducer. Мы в порядке!

Вам интересно, что ваш браузер сообщает вам сейчас?

Еще одна большая красная ошибка!

Не пугайтесь - это просто Redux пытается вам помочь. Если мы внимательно прочитаем, то увидим, что в нашей функции combineReducers отсутствует редуктор.

Имеет смысл.

Давайте сделаем наш первый настоящий редуктор.

У редукторов есть два аргумента:

  1. Текущий state, который мы изначально установили на пустой Object {}.
  2. An action.

Редуктор всегда будет возвращать состояние.

Давайте импортируем наш app_reducer.js и передадим его в качестве аргумента combineReducer.

Как вы, наверное, знаете, мы можем передавать объекты в качестве аргументов функции.

Сейчас наше состояние называется astronomy. После вызова mapStateToProps наши данные будут внутри this.props.astronomy в наших «подключенных» компонентах.

Наш браузер перестал показывать красный цвет - должно быть, мы что-то делаем правильно!

Мы создали наши store и наши reducer. Теперь мы должны создать наш action и, наконец, связать его с нашим компонентом React.

Всегда важно видеть, какую проблему мы пытаемся решить - это получение астрономических данных из NASA API.

Мы медленно, но верно отделяем наше состояние от React и позволяем Redux обрабатывать его.

Далее: Действия !

Ознакомьтесь с документацией Redux, если вам интересно узнать больше о Редукторах.

Создание действий

В документации есть отличный способ объяснения действий:

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

Как и в случае с редукторами, начнем с создания нового каталога внутри src с именем actions.

В каталоге actions у нас будет файл с именем fetch_data.js.

Сверху донизу:

  • Импортируем Axios для извлечения данных.
  • У нас есть функция fetchData, которую мы экспортируем.
  • Внутри функции мы объявили пару констант для наших конечных точек, как и раньше.

Действие вернет простой объект, содержащий следующее:

  1. Тип действия
    Это необходимо для того, чтобы редуктор распознал наше действие.
  2. Полезная нагрузка
    В данном случае это данные, полученные с конечной точки.

Теперь нам нужно связать его с нашим компонентом React. Мы можем вызвать action как this.props.fetchData() и получить желаемые данные.

Я знаю, что просто сделать GET запрос - это много хлопот. Но изучение Redux значительно упростит понимание наших приложений.

Теперь нам нужно установить зависимость для разрешения нашего promise.

Redux не умеет справляться с асинхронными действиями. Итак, нам нужно установить промежуточное ПО.

$ yarn add redux-promise

store принимает middleware, а промежуточное ПО зачаровывает наше приложение в фоновом режиме.

Применение промежуточного программного обеспечения Redux

Здесь мы делаем три вещи:

  1. Импортировать applyMiddleware из 'redux'.
  2. Импортировать promise из 'redux-promise'.
  3. Передайте второй аргумент внутри нашей функции createStore(). Аргумент называется applyMiddleware(), и он принимает любое промежуточное ПО. Мы передаем промежуточное ПО promise внутри функции applyMiddleware().

Вернуться к редукторам

Мы объявили свое действие, но наш редуктор ничего об этом не знает. Давай исправим это!

Мы собираемся добавить switch() оператор, который проверяет, какие действия были запущены, и действовать соответствующим образом.

Действия и редукторы по умолчанию подключаются в Redux. Нам не нужно их склеивать.

Помните, у нас было действие, возвращающее объект с реквизитом?

Одним из этих свойств был type: ‘FETCH_DATA’.. В редукторе мы проверяем, действительно ли запущенное действие соответствует типу. Если это так, мы возвращаем новый state.

Мы используем оператор распространения - мы передаем наше состояние внутри нового массива с action.payload, который является данными запроса.

Помните, что мы не изменяем состояние, изменение состояния - это антипаттерн! Всегда возвращайте только что созданное состояние.

Простые примеры:

Плохо (изменение исходного состояния)

case('FETCH_DATA'):
  state = action.payload.data
  return state;

Почему плохо? Потому что мы присваиваем существующий state новому значению.

Хорошо (без изменения исходного состояния)

case 'FETCH_DATA':
   const newState = Object.assign({}, ...state, action.payload.data)
   return newState;

Почему хорошо? Потому что мы создаем новый объект , содержащий новый state и данные.

Наш следующий шаг - последний шаг. Мы можем связать это с нашим компонентом React!

Подключение Redux с помощью React Views

Мы почти закончили, осталось закончить еще несколько дел.

Очистим наш AstronomyContainer.js?

Заметили, что мы убрали все state внутри нашего компонента? Уже нет this.state!

Это именно то, что вам нужно в приложении Redux.

С помощью специальной функции connect() мы можем буквально связать React с Redux.

Импортируйте метод connect из react-redux и экспортируйте метод внизу. Connect() принимает два аргумента - mapStateToProps и mapDispatchToProps.

  • mapStateToProps
    Делает именно то, что написано. Он отображает состояние Redux на свойства React.
  • mapDispatchToProps
    Преобразует действия Redux в свойства React.

Почему наш первый аргумент внутри connect null?

Метод connect ожидает передачи mapStateToProps функции. Но мы еще не написали. Итак, мы передаем временный null.

mapStateToProps

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

mapDispatchToProps

mapDispatchToProps позволяет нам сопоставить наши действия с props. В этом случае он получает наши данные.

Эта функция возвращает объект. Он принимает текущий state в качестве аргумента и отображает опору в astronomy из нашего редуктора.

У нас был astronomy редуктор внутри src/reducers/index.js. Мы просто сопоставляем ему свой реквизит.

const rootReducer = combineReducers({
 astronomy: AppReducer
})

Давайте проверим, работает ли this.props.astronomy. Он должен показать пустой объект.

Не волнуйтесь, если вы не можете вспомнить, почему это пустой объект - Redux вначале подавляет.

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

export default function(state = {}, action) {
 return state;
}

Заключительный шаг - выполнение действий (получение данных)

Реализовать действия довольно просто.

Напоминание: наше действие находится в src/actions/fetch_data.js - внутри файла есть функция с именем fetchData(), которая выполняет GET запрос.

Вот три вещи, которые нам нужно сделать, чтобы вызвать наш action и, наконец, получить наши данные.

  1. Импортируйте действие из src/actions/fetch_data.js.
  2. Передайте наше действие как аргумент внутри функции connect.
  3. Вызовите действие внутри метода React lifecycle. В данном случае это ComponentWillMount().

Хорошо, давай приступим.

Взгляните на свой браузер прямо сейчас!

Оно работает! Вам удалось провести рефакторинг вашего приложения для использования Redux.

Заметили, что внутри наших компонентов React нет this.state? Мы позволяем Redux обрабатывать наше состояние!

Спасибо, что дожили до конца! Вы узнали о Redux, редукторах, Actions, Store, Provider, Middleware, mapStateToProps(), mapDispatchToProps() и connect(), создав классное приложение для астрономии.

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

Ресурсы





Большое спасибо за чтение, оставайтесь классными! ❤