Основи Redux, частина 3: Стан, дії та редуктори #

Що ви дізнаєтесь

  • Як визначити значення стану, які містять дані вашого додатка
  • Як визначити об’єкти дій, які описують, що відбувається у вашому додатку
  • Як писати функції редуктора, які обчислюють оновлений стан на основі існуючого стану та дій

  • Знайомство з ключовими термінами та поняттями Redux, такими як "дії", "редуктори", "зберігання" та "відправлення". (Побачити Частина 2: Концепції Redux та потік даних для пояснень цих термінів.)

Вступ #

У частині 2: Концепції Redux та потік даних ми розглянули, як Redux може допомогти нам створювати сервісні програми, надаючи нам єдине центральне місце для глобального стану додатків. Ми також говорили про основні концепції Redux, такі як диспетчеризація об'єктів дій та використання функцій редуктора, які повертають нові значення стану.

Тепер, коли ви трохи уявляєте, що це за штуки, настав час застосувати ці знання на практиці. Ми збираємося створити невеликий приклад програми, щоб побачити, як ці твори насправді працюють разом.

Приклад програми не призначений як повний готовий до виробництва проект. Мета полягає в тому, щоб допомогти вам вивчити основні API Redux та схеми використання, і спрямувати вас у правильному напрямку, використовуючи деякі обмежені приклади. Крім того, деякі з попередніх творів, які ми будуємо, буде оновлено пізніше, щоб показати кращі способи зробити щось. Будь ласка, прочитайте весь підручник, щоб побачити всі використовувані концепції.

Налаштування проекту #

Для цього підручника ми створили заздалегідь налаштований початковий проект, у якому вже налаштовано React, який включає деякий стиль за замовчуванням і має підроблений REST API, що дозволить нам писати фактичні запити API у нашому додатку. Ви будете використовувати це як основу для написання власне коду програми.

Для початку ви можете відкрити та розгалужити цей CodeSandbox:

Ви також можете клонувати той самий проект із цього репозиторію Github. Після клонування репо, ви можете встановити інструменти для проекту за допомогою npm install і запустити його з npm start .

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

Створення нового проекту Redux + React #

Закінчивши цей підручник, ви, мабуть, захочете спробувати працювати над власними проектами. Ми рекомендуємо використовувати шаблони Redux для Create-React-App як найшвидший спосіб створити новий проект Redux + React. Він поставляється з уже налаштованими Redux Toolkit та React-Redux, використовуючи модернізовану версію прикладу програми "counter", який ви бачили в Частині 1. Це дозволяє перейти безпосередньо до написання власного коду програми, не додаючи пакунків Redux та не налаштовуючи магазин.

Якщо ви хочете знати конкретні подробиці про те, як додати Redux до проекту, див. Це пояснення:

Детальне пояснення: Додавання Redux до проекту React

Шаблон Redux для CRA поставляється з уже налаштованими Redux Toolkit та React-Redux. Якщо ви створюєте новий проект з нуля без цього шаблону, виконайте такі дії:

  • Додайте пакети @ reduxjs/toolkit та response-redux
  • Створіть магазин Redux, використовуючи RTK's configureStore API, і передайте принаймні одну функцію редуктора
  • Імпортуйте сховище Redux у файл точки входу програми (наприклад, src/index.js)
  • Оберніть ваш кореневий компонент React файлом

компонент від React-Redux, наприклад:

Вивчення початкового проекту №

Цей початковий проект базується на стандартному шаблоні проекту Create-React-App з деякими змінами.

Давайте швидко розглянемо, що містить початковий проект:

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

З цим давайте почнемо!

Запуск програми Todo Example #

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

Визначення вимог №

Почнемо з того, що з’ясуємо початкові бізнес-вимоги до цієї програми:

  • Інтерфейс користувача повинен складатися з трьох основних розділів:
    • Поле введення, яке дозволяє користувачеві вводити текст нового завдання
    • Список усіх існуючих пунктів завдання
    • Розділ нижнього колонтитула, який показує кількість незавершених завдань та параметри фільтрації
  • Елементи списку Todo повинні мати прапорець, який перемикає їх статус "завершено". Ми також повинні мати можливість додавати кольоровий тег категорії для заздалегідь визначеного списку кольорів та видаляти всі завдання.
  • Лічильник повинен збільшувати кількість активних завдань: "0 елементів", "1 елемент", "3 елементи" тощо
  • Повинні бути кнопки, щоб позначити всі завдання як виконані та очистити всі виконані завдання, видаливши їх
  • Повинно бути два способи відфільтрувати відображені тодо у списку:
    • Фільтрування на основі показу тотосів "Усі", "Активні" та "Завершені"
    • Фільтрування на основі вибору одного або кількох кольорів та показу будь-яких тодо, тег яких відповідає цим кольорам

Пізніше ми додамо ще деякі вимоги, але цього достатньо для початку.

Кінцевою метою є програма, яка повинна виглядати так:

redux

Розробка державних цінностей #

Одним із основних принципів React та Redux є такий ваш інтерфейс користувача повинен базуватися на вашому штаті. Отже, один із підходів до розробки програми полягає в тому, щоб спочатку продумати весь стан, необхідний для опису роботи програми. Також непогано спробувати описати свій інтерфейс із якомога меншою кількістю значень у стані, щоб було менше даних, необхідних для відстеження та оновлення.

Концептуально існує два основні аспекти цієї програми:

  • Фактичний список поточних завдань
  • Поточні параметри фільтрації

Нам також потрібно буде відстежувати дані, які користувач вводить у поле введення "Add Todo", але це менш важливо, і ми з цим займемося пізніше.

Для кожного завдання, нам потрібно зберігати кілька відомостей:

  • Текст, який ввів користувач
  • Логічний прапор із запитом, завершено це чи ні
  • Унікальне значення ідентифікатора
  • Категорія кольорів, якщо вибрано

Нашу поведінку фільтрації, можливо, можна описати за допомогою деяких перелічених значень:

  • Завершений статус: "Усі", "Активний" та "Завершений"
  • Кольори: "Червоний", "Жовтий", "Зелений", "Синій", "Помаранчевий", "Фіолетовий"

Переглядаючи ці значення, ми можемо також сказати, що тодо - це "стан програми" (основні дані, з якими працює програма), тоді як значення фільтрації - "стан інтерфейсу користувача" (стан, який описує, що додаток робить зараз). Може бути корисно подумати про ці різні категорії категорій, щоб допомогти зрозуміти, як використовуються різні частини держави.

Розробка державної структури #

З Redux, наш стан програми завжди зберігається в простих об'єктах і масивах JavaScript. Це означає, що ви не можете поміщати інші речі у стан Redux - жодних екземплярів класів, вбудованих типів JS, таких як Map/Set Promise/Date, функцій чи чогось іншого, що не є простими даними JS.

Кореневе значення стану Redux майже завжди є простим об'єктом JS, з іншими даними, вкладеними всередину нього.

Виходячи з цієї інформації, ми тепер маємо змогу описати типи значень, які ми повинні мати в нашому стані Redux:

  • По-перше, нам потрібен масив об’єктів todo item. Кожен елемент повинен мати такі поля:
    • id: унікальний номер
    • text: текст, введений користувачем
    • завершено: логічний прапор
    • колір: необов’язкова категорія кольорів
  • Потім нам потрібно описати наші параметри фільтрування. Нам потрібно мати:
    • Поточне значення "завершеного" фільтра
    • Масив із вибраних категорій кольорів

Отже, ось як може виглядати приклад стану нашого додатка:

Важливо зазначити, що нормально мати інші державні цінності поза Redux!. Цей приклад поки що достатньо малий, щоб насправді весь наш стан знаходився в магазині Redux, але, як ми побачимо пізніше, деякі дані насправді не потрібно зберігати в Redux (наприклад, "це спадне меню відкрито?" Або "поточне значення введення форми").

Розробка дій #

Дії є звичайними об'єктами JavaScript, які мають поле типу. Як вже згадувалося раніше, Ви можете сприймати дію як подію, яка описує те, що сталося в додатку.

Подібно до того, як ми розробили державну структуру на основі вимог програми, ми також повинні мати змогу скласти перелік деяких дій, які описують те, що відбувається:

  • Додайте новий запис до тексту на основі тексту, який ввів користувач
  • Переключити завершений статус завдання
  • Виберіть кольорову категорію для завдання
  • Видалити завдання
  • Позначити всі завдання як виконані
  • Очистити всі виконані завдання
  • Виберіть інше "завершене" значення фільтра
  • Додайте новий кольоровий фільтр
  • Видаліть кольоровий фільтр

Зазвичай ми додаємо будь-які додаткові дані, необхідні для опису того, що відбувається, у поле action.payload. Це може бути число, рядок або об’єкт із кількома полями всередині.

Магазину Redux байдуже, яким буде фактичний текст поля action.type. Однак ваш власний код перегляне action.type, щоб побачити, чи потрібно оновлення. Крім того, ви часто будете переглядати рядки типів дій у розширенні Redux DevTools під час налагодження, щоб побачити, що відбувається у вашому додатку. Отже, спробуйте вибрати види дій, які читаються, і чітко описують те, що відбувається - набагато легше буде зрозуміти речі, коли подивишся на них пізніше!

На основі цього списку речей, які можуть статися, ми можемо створити список дій, які використовуватиме наша програма:

У цьому випадку дії в основному мають по одній додатковій частині даних поштучно, тому ми можемо помістити це безпосередньо в поле action.payload. Ми могли б розділити поведінку кольорового фільтра на дві дії, одну для "додано" та одну для "видалено", але в цьому випадку ми будемо робити це як одну дію з додатковим полем всередині спеціально, щоб показати, що ми можемо мати об'єкти як корисне навантаження дії.

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

Редуктори для написання

Тепер, коли ми знаємо, як виглядає наша державна структура та наші дії, настав час написати свій перший редуктор.

Редуктори - це функції, які приймають поточний стан та дію як аргументи та повертають результат нового стану. Іншими словами, (стан, дія) => newState .

Створення кореневого редуктора #

Додаток Redux насправді має лише одну функцію редуктора: функцію "кореневого редуктора" що ви перейдете до createStore пізніше. Ця одна функція кореневого редуктора відповідає за обробку всіх відправлених дій та обчислення кожного нового результату кожного разу.

Почнемо із створення файлу reducer.js у папці src, поряд з index.js та App.js .

Кожен редуктор потребує певного початкового стану, тому для початку ми додамо кілька підроблених записів. Тоді ми можемо написати схему логіки всередині функції редуктора: