З 0 до 1

З 0 до 1. Розбираємося з Redux +13

  • 30.10.15 7:52 •
  • mishapsv •
  • # 269831 •
  • Хабрахабр •
  • З пісочниці •
  • 12 •

- такий же як Forbes, тільки краще.

Коли вийшла версія 1.0 Redux, я вирішив витратити трохи часу на серію розповідей про мій досвід роботи з ним. Нещодавно я мав вибрати "реалізацію Flux" для клієнтського додатка і до сих пір із задоволенням працюю з Redux.

Чому Redux?

Redux пропонує думати про програму, як про початковий стан модифікуються послідовністю дій (actions), що я вважаю дійсно хорошим підходом для складних веб-додатків, що відкриває багато можливостей.

Звичайно, ви можете знайти більше інформації про Redux, його архітектурі і ролі кожного компонента в документації.

Створюємо список друзів з React і Redux


Сьогодні ми сфокусуємось на покроковому створенні вашого першого додатка, що використовує Редакс і реактив: створимо простий список друзів з нуля.

Ви можете знайти готовий код тут.

1. Установка

Є збірки вже з встановленим Redux, але, я думаю, важливо зрозуміти роль кожної бібліотеки.

1.1 Додамо redux, react-redux і redux-devtools


Нам потрібно встановити три пакети:

  • Redux: сама бібліотека
  • React-redux: зв'язка з React
  • Redux-devtools: опціонально, дає деякі корисні інструменти для розробки.
1.2 Структура директорій


Хоча те, що ми будемо робити, досить просто, давайте створимо структуру директорій як для реального застосування.


Ми бачитиме більш детально роль кожної з директорій, коли будемо створювати додаток. Ми перемістили App.js в директорію containers, так що потрібно буде налаштувати імпорт statement в index.js.

1.3 Підключаємо Redux

Нам потрібно включити devtools тільки для оточення розробки, так що модифікуємо webpack.config.js як тут:


Коли ми запустимо наш додаток з DEBUG = true npm start. це включить __DEV__ прапор, який ми можемо використовувати в нашому додатку. Ми можемо підключити devtools наступним чином:


Ми робимо тут дві речі. Ми переобумовленої createStore використовуючи створену функцію, яка дозволяє нам застосовувати множинні store enhancers. таких як devTools. Ми також включаємо функцію renderDevTools, яка рендерить DebugPanel.

Зараз нам потрібно модифікувати App.js для з'єднання з redux. Для цього ми будемо використовувати Provider з react-redux. Це зробить наш екземпляр сховища доступним для всіх компонентів, які розташовуються в Provider компоненті. Не потрібно турбуватися про дивно виглядає функції, її мета використовувати "контекст" функції реактив для створення сховища, доступного для всіх дітей (компонентів).


Для створення сховища ми використовуємо createStore функцію, яку ми визначили в devTools файлі, як map всіх наших редьюсеров.

ES6 синтаксис import * as reducers дозволяє нам отримувати об'єкт у вигляді . Це відмінно підходить для завдання аргументів для combineReducers.


У нашому додатку App.js - зовнішня обгортка для Redux і FriendListApp - кореневої компонент для нашого застосування. Після створення простого 'Hello world' в FriendListApp.js, ми можемо нарешті запустити наш додаток з redux і devTools. Ви повинен отримати це (без стилів).

З 0 до 1

Хоча це просто 'Hello world' додаток, у нас включений Hot Reloading, тобто ви можете модифікувати текст і отримувати автоматичне оновлення на екрані. Як ви можете бачити, devtools справа показує порожні сховища. Заповнимо їх!

2. Створюємо додаток


Тепер, коли зроблені всі настройки, ми можемо сфокусуватися на самому додатку.

2.1 Дії та генератори дій


Дії - це структура, яка передає дані з вашого застосування в сховище. За угодою, дії повинні мати строкове поле type. яке вказує на тип виконуваного дії. Визначати цей тип в іншому модулі? -? Хороша практика, і це змушує нас замислитися заздалегідь про те, що ми будемо робити в нашому додатку.


Як ви можете бачити, це дуже виразний шлях визначення області дій нашого додатку, який буде дозволяти нам додавати друзів, відзначати їх як «обраних» або видаляти їх з нашого списку.

Генератори дій - функції, які створюють дії. У Redux генератори дій є чистими функціями, що робить їх портативними і простими для тестування, тому що вони не мають сайд-ефектів.

Ми помістимо їх в папку дій, але не забувайте, що це різні поняття.


Як бачите, дії досить мінімалістичні. Щоб додати елемент, ми повідомляємо все властивості (тут ми маємо справу лише з name), а для інших ми посилаємося на id. У більш складному додатку, ми, можливо, мали б справу з асинхронними діями, але це тема для іншої статті ...

2.2 Редьюсери


Редьюсери відповідають за модифікації станів додатки. Вони - чисті функції з наступним видом (previousState, action) => newState. Дуже важливо розуміти, що ви не повинні ніколи (взагалі ніколи) змінювати початковий стан в редьюсере. Замість цього ви можете створювати нові об'єкти на базі властивостей previousState. В іншому випадку це може мати небажані наслідки. Також, це не місце для обробки сайд-ефектів, таких як роутинг або асинхронні виклики.

Ми, для початку, визначаємо вид стану нашого застосування в initialState:


Станом може бути все, що ми захочемо, ми можемо просто зберегти масив друзів. Але це рішення погано масштабується, так що ми будемо використовувати масив id і map друзів. Про це можна почитати в normalizr.

Тепер нам потрібно написати актуальний редьюсер. Ми скористаємося можливостями ES6 для завдання аргументів за замовчуванням для обробки випадків, коли стан не визначено. Це допоможе зрозуміти як записати редьюсер, в даному випадку я використовую switch.


Якщо ви не знайомі з синтаксисом ES6 / 7, то можливо вам буде важко це прочитати. Оскільки нам потрібно повернути новий стан об'єкта, як правило використовують Object.assign або Spread operator.

Що тут відбувається: ми визначаємо новий id. У реальному додатку ми, можливо, візьмемо його з сервера або, як мінімум, переконаємося, що він унікальний. Потім ми використовуємо concat щоб додати цей новий id в наш id-лист. Concat додасть новий масив і не змінить оригінальний.

Computed properties? -? Це зручні можливості ES6, які дозволяють нам простіше створювати динамічні key в friendsById об'єкті з [newId].

Як ви можете бачити, незважаючи на синтаксис, який може спочатку збентежити, логіка проста. Ви задаєте стан і отримуєте назад новий стан. Важливо: ні в одній точці цього процесу не змінювати попередній стан.

Окей, давайте повернемося і створимо редьюсери для двох інших дій:


Я додав lodash, щоб спростити управління об'єктами. Як завжди, в цих двох прикладах, важливо не змінювати попередній стан, тому ми використовуємо функцію, яка повертає новий об'єкт. Для прикладу, замість delete state.friendsById [action.id]. ми використовуємо _.omit функцію.

Ви також можете помітити, що spread оператор дозволяє нам маніпулювати тільки тими станами, яке нам потрібно змінити.

Redux не важливо, як ви зберігаєте дані, так що можна використовувати Immutable.js.

Тепер ви можете пограти зі сховищем минаючи інтерфейс, шляхом виклику dispatch вручну в нашому App.js.


Ви побачите в devTools дії, з ними можна пограти в реальному часі.

З 0 до 1

3. Створюємо інтерфейс


Оскільки цей урок не про це, я пропустив створення React-компонентів і сфокусувався лише на Redax. Ми маємо три простих компонента:

  • FriendList список друзів

      • friends: array масив друзів

    • FriendListItem елемент одного друга

      • name: string ім'я одного
      • starred: boolean показує зірочку, якщо один відзначений, як обраний
      • starFriend: function виклик, який спрацьовує, коли користувач клацає на зірочки
      • deleteFriend: function виклик, який спрацьовує, коли користувач клацає на кошик

    • AddFriendInput поле для введення нових імен
      • addFriend: function виклик, що спрацьовує при натисканні введення


    У Redux вважається хорошою практикою робити по можливості більшість компонентів "дурними". Тобто чим менше компонентів пов'язані з Redux, тим краще.

    Тут FriendListApp буде єдиним "розумним" компонентом.


    Це частина нового синтаксису ES7, звана декоратор. Це зручний спосіб виклику функції вищого порядку. Буде еквівалентна connect (select) (FriendListApp); де select - функція, яка повертає те, що ми тут зробили.


    Ми використовуємо bindActionCreators. щоб обернути наші генератори дій викликом dispatch. Мета - передати генератори дій іншим нашим компонентів без надання dispatch об'єкта (зберігаючи їх дурними).

    Те, що станеться далі - стандартний підхід для React. Ми прив'яжемо функції до onClick, onChange або onKeyDown властивостями, щоб обробити дії користувача.

    Якщо ви зацікавилися, як це зробити, ти можете подивитися весь код.

    Зараз ви можете відчути магію роботи redux / react додатки. Як зображено на GIF, ви логгіруете всі дії.
    Розробляти зручніше, коли ти можеш робити якісь дії, знаходити баги, повертатися, виправляти їх і повторювати вже виправлену послідовність ...