Створення actions · redux-course-ru

ОБНОВЛЕННЯ 2018: Вийшло друге видання (сучасний код та версії пакетів, дане видання ЗАСТАРІЛО)

Створення actions

Нарешті ми підходимо до питання взаємодії з користувачем програми. Практично будь-яка дія користувача в інтерфейсі =направлення дії (dispatch actions)

Натисніть кнопку року, наш додаток:

  • встановлює заголовок
  • завантажує фото цього року

Зараз пропоную розглянути встановлення заголовка. Завантаження фотографій вимагає виконання асинхронного запиту, а щоб дістатися до цього, ми повинні розглянути кілька цікавих речей. До того ж, встановлення заголовка відмінно показує на простому прикладі, як обертаються дані всередині redux-додатки, а саме:

  1. Додаток отримав початковий стан (initial state)
  2. Користувач натиснувши кнопку відправив дію (dispatch action)
  3. Відповідний редьюсер оновив частину додатку, згідно з тим, що дізнався від дії.
  4. Програма змінилася і тепер відображає новий стан.
  5. . (Все повторюється по колу, з пункту 2)

Це і є однонаправлений потік даних.

Створимо page action:

Нагадую, що поля type і payload - лише "негласна" угода. Трохи про це можна почитати англійською тут.

Виправимо редьюсер page:

Зверніть увагу, у аргументах у функції page вказано другий аргумент - action. Це стандартні аргументи redux reducer'а. Завдяки цьому ми можемо легко обробляти різні дії за їх типом, потрапляючи в потрібну секцію case оператора switch.

Також зверніть увагу, що ми незмінили об'єкт state, а повернулиновий з полем year рівним action.payload (а значитьроком, обраним користувачем).

Додаємо виклик actions з компонентів

У нас є action, і є reducer готовий змінити state програми (так, я навмисне пишу іноді ці слова англійською). Але наш компонент не знає, як звернутися до необхідної дії.

Відповідно до таблиці з минулого розділу: для зміни даних, наш компонент Page.js повинен викликати callback з this.props, а наш контейнер* App.js - відправляти дію (dispatch action).

* я говорю, контейнер, хоча правильніше називати контейнером, але так як він генерується функцією connect на основі App.js, вважаю це допустимим.

connect першим аргументом приймає "мапінг" (відповідність) state до props, а другим мапінг dispatch до props. Як би дико це не звучало, на практиці це означає, що нам достатньо передати другий аргумент.

Почнемо з аналізу mapDispatchToProps . Всередині функції ми використовували допоміжну функцію з redux - bindActionCreators (оф. документація, яка дозволила викликати setYear, якщо висловитися просто з деякими припущеннями як:

Тим самим, необхідна зміна прослуховується в redux store, і в нашому редьюсері Page відповідно.

Отже, після виконання connect(mapStateToProps, mapDispatchToProps)(App) ми отримали в App.js нові властивості (props), що наочно демонструє вкладка "React" у chrome dev tools.

action

Додавши setYear у властивості Page.js , не важко використовувати необхідний action з компонента, який як і раніше знати нічого не знає про redux.

UPDATE [18.03.16]: властивість innerText наведена в коді нижче - нестандартна, тому з ним можуть виникнути проблеми в деяких браузерах. Замість нього можна використовувати - textContent.

Власне код компонентаPage як і раніше дуже простий. Рядок ::this.onYearBtnClick === this.onYearBtnClick.bind(this) , і потрібна так як React з версії 0.14.x не прив'язує цей компонент.

Використання подвійної двокрапки - це можливість ES7 (experimental), яка доступна в babel з налаштуванням stage=0 (для тих хто писав код, починаючи з розділу "Підготовка" - все вже налаштовано, дивись файл .babelrc)

Глава видалася досить довгою, а найгірше, що ми написали "кіпу" коду, лише для оновлення цифри в заголовку. Де прибуток, як кажуть?

Профіт виявиться далі, коли ваша програма розростеться. Коли його потрібно буде підтримувати і додавати нові фічі. За рахунок однонаправленого потоку даних (користувач клікнув - дія викликалася - ред'юсер змінив стан - компонент відмалював зміни) навіть у додатку, написаному давно, у вас вийде дуже швидко розібратися і внести необхідні оновлення, які вимагає бізнес. До того ж такий підхід відмінно працює і для командної роботи.