Создание actions
Last updated
Was this helpful?
Last updated
Was this helpful?
ОБНОВЛЕНИЕ 2018: Вышло (современный код и версии пакетов, данное издание УСТАРЕЛО)
На так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы, !
Наконец-то мы подходим к вопросу взаимодействия с пользователем приложения. Практически любое действие пользователя в интерфейсе = отправка действия (dispatch actions)
По клику на кнопку года, наше приложение:
устанавливает заголовок
загружает фото этого года
Сейчас предлагаю рассмотреть установку заголовка. Загрузка фото требует выполнения асинхронного запроса, а чтобы добраться до этого, мы должны рассмотреть несколько интересных вещей. К тому же, установка заголовка отлично показывает на простом примере, как вращаются данные внутри redux-приложения, а именно: 1. Приложение получило изначальное состояние (initial state) 2. Пользователь нажав кнопку, отправил действие (dispatch action) 3. Соответсвующий редьюсер обновил часть приложения, в согласии с тем, что узнал от действия. 4. Приложение изменилось и теперь отражает новое состояние. 5. ... (все повторяется по кругу, с пункта 2)
Это и есть однонаправленный поток данных.
Создадим page action:
src/actions/PageActions.js
Поправим редьюсер page:
src/reducers/page.js
Обратите внимание, в аргументах у функции page указан второй аргумент - action. Это стандартные аргументы redux reducer'а. Благодаря этому, мы можем легко обрабатывать различные действия по их типу, попадая в нужную секцию case оператора switch.
Так же обратите внимание, что мы не изменили объект state, а вернули новый с полем year равным action.payload (а значит годом, выбранным пользователем).
У нас есть action, и есть reducer готовый изменить state приложения (да, я нарочно пишу иногда эти слова по-английски). Но наш компонент не знает как обратиться к необходимому действию.
Согласно таблице из прошлого раздела: для изменения данных, наш компонент Page.js, должен вызывать callback из this.props, а наш контейнер* App.js - отправлять действие (dispatch action).
* я говорю, контейнер, хотя правильнее называть контейнером <Connect(App) />
, но так как он генерируется функцией connect на основе App.js, считаю это допустимым.
connect
, первым аргументом принимает "маппинг" (соответствие) state к props, а вторым маппинг dispatch к props. Как бы дико это не звучало, на практике это значит, что нам достаточно передать второй аргумент.
Исправим App.js
src/containers/App.js
Тем самым необходимое изменение прослушивается в redux store, и в нашем редьюсере Page соответственно.
Добавив setYear в свойства Page.js , не составит труда использовать необходимый action из компонента, который по прежнему знать ничего не знает о redux.
src/components/Page.js
Собственно, код компонента Page по прежнему очень простой. Строка ::this.onYearBtnClick
=== this.onYearBtnClick.bind(this)
, и нужна так как React с версии 0.14.x не привязывает this к компоненту.
Глава выдалась достаточно длинной, а хуже всего, что мы написали "кипу" кода, всего лишь для обновления цифры в заголовке. Где профит, как говорится?
Профит обнаружится дальше, когда ваше приложение разрастется. Когда его будет необходимо поддерживать и добавлять новые фичи. За счет однонаправленного потока данных (юзер кликнул - действие вызвалось - редьюсер изменил состояние - компонент отрисовал изменения) даже в приложении, написанном давно, у вас получится очень быстро разобраться и внести необходимые обновления, которые требует бизнес. К тому же, такой подход отлично работает и для командной работы.
Напоминаю, что поля type и payload - всего лишь "негласное" соглашение. Немного об этом, можно почитать на английском .
Из документации функции , нам так же становится ясно, что с помощью этой функции мы можем не только подписаться на обновления данных, но и "прокинуть" наши actions в контейнер.
Начнем с разбора mapDispatchToProps
. Внутри функции мы использовали вспомогательную функцию из redux - bindActionCreators (, которая позволила вызывать setYear, если выразиться просто с некоторыми допущениями как:
Следовательно, после выполнения connect(mapStateToProps, mapDispatchToProps)(App)
, мы получили в App.js новые свойства (props), что наглядно демонстрирует вкладка "React" в chrome dev tools.
[18.03.16]: свойство приведенное в коде ниже - нестандартное, поэтому с ним могут возникнуть проблемы в некоторых браузерах. Вместо него, вы можете использовать - .
Использование двойного двоеточия - это возможность ES7 (), которая доступна в babel с настройкой stage=0
(для тех кто писал код, начиная с раздела "Подготовка" - все уже настроено, смотри файл .babelrc)