Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Автоматное программирование JS: React

Тема конечных автоматов занимает центральную роль во фронтенд-разработке. Интерактивные элементы всегда вовлечены в процессы, связанные с изменением состояний. Модальные окна бывают открытые и скрытые, кнопка нажата, отжата или заблокирована (например, во время AJAX-запроса). Примеров бесконечное множество. Нередко эти автоматы зависят друг от друга, что порождает иерархию автоматов. Например, возможность взаимодействовать с элементом на экране может появляться только после нажатия кнопки «редактировать».

В React работа с автоматами проста до безобразия и в большинстве случаев не требует использования специальных библиотек. Возьмём, к примеру, кнопку, которая отвечает за показ куска текста. Её состояния можно описать так:

  • По умолчанию текст скрыт (состояние hidden)
  • Клик по кнопке отображает текст (состояние shown)
  • Повторный клик прячет текст (hidden)

В данном случае у кнопки два состояния, поэтому можно упростить задачу и использовать флаг как индикатор состояния. Назовём его как isShown.

Использовать флаги c булевыми значениями очень не рекомендуется в бэкенде, когда состояние хранится в базе. Цена изменения автомата слишком высока (изменение типа колонки с boolean на string), поэтому даже в случае бинарной логики лучше делать полноценный автомат с именованными состояниями. Другими словами, для хранения состояния используйте не булево поле (с true/false), а текстовое поле, в котором будет содержаться полное название состояния. Например, если статья может находиться в двух состояниях («опубликована» или «не опубликована»), то нужно делать не поле 'published: bool' со значениями true и false, а поле 'publishing_state' со значениями 'published' и 'unpublished'

See the Pen js_react_fsm by Hexlet (@hexlet) on CodePen.

Большая часть кода в React (как и во всем фронтенде) выглядит именно так, как в примере выше. События порождают изменения состояния в данных, на основе которых, в свою очередь, меняется представление. Количество конечных автоматов во фронтенд-приложениях растёт с астрономической скоростью, главное их видеть и выделять явно.

Структура состояния

Данные, с которыми работает React, как правило, приходят из бэкенда. И эти данные тоже участвуют в разных процессах и находятся в разных состояниях. Например, статья может быть опубликована, а может быть и нет. И в зависимости от того, в каком она состоянии, рисуется UI. И здесь начинается самое интересное. Конкретно состояние опубликованности статьи не является частью UI, но UI использует это состояние, а при изменениях оно синхронизируется на фронтенде и бэкенде. Но в UI часто появляются состояния, которые отвечают исключительно за внешний вид, но не являются частью данных.

Если предположить, что данные, пришедшие с бэкенда, внутри нашего объекта-состояния хранятся как список под ключом items, то возникает вопрос: куда записывать данные, отвечающие за состояние UI? То есть те самые состояния, которые появляются только при взаимодействии с пользователем и не используются на серверной стороне?

Пример: с бэкенда приходит статья такой структуры: { id: 3, name: 'How to program', state: 'published' }. Она отправляется в items. А в UI есть возможность зайти в её редактирование и для этого используется флаг (состояние) isEditing, который существует только на экране. Вопрос: где хранить эту переменную?

Самый простой вариант: изменить саму статью внутри items так, чтобы она имела такой вид: { id: 3, name: 'How to program', state: 'published', isEditing: true }. Хотя на первый взгляд он и кажется разумным, проблем он привносит больше, чем пользы. В основном эти проблемы связаны с задачами синхронизации. Иногда бывает нужно отправить всю статью на сервер (после изменений), а иногда перечитать её заново с бэкенда. В такой ситуации нужно будет либо извлекать только нужные данные, либо постоянно делать «мердж» (слияние), чтобы не потерять состояние UI. Практика показала, что гораздо проще добавлять отдельный список исключительно под задачи хранения состояния UI. То есть в стейте добавить отдельный список, например, под названием itemUIStates, и для статьи в него добавится элемент { articleId: 3, isEditing: true }.


Дополнительные материалы

  1. Почему сложно программировать UI
  2. Курс "Автоматное программирование"
  3. Урок "Процессы и автоматы, их описывающие"

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 6 300 ₽ в месяц
Разработка фронтенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 21 марта
профессия
от 9 900 ₽ в месяц
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
16 месяцев
с нуля
Старт 21 марта

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»