Какова реальная разница между редуксом и конечным автоматом (например, xstate)?

Я работаю над исследованием одного интерфейсного приложения средней сложности. На данный момент он написан на чистом javascript, в нем много разных сообщений на основе событий, соединяющих несколько основных частей этого приложения.

Мы решили, что, очевидно, нам нужно реализовать некоторый контейнер состояний для этого приложения в рамках дальнейшего рефакторинга. Ранее у меня был некоторый опыт работы с RedEx и с магазином ngrx (который фактически следует тем же принципам).

Redux - вариант для нас, но один из разработчиков предложил использовать конечный автомат, в частности библиотеку xstate.

Я никогда не работал с этой вещью, поэтому я нашел ее интересной и начал читать документацию и искать разные примеры. Выглядело многообещающе и мощно, но в какой-то момент я понял, что не вижу значительной разницы между ним и редукцией.

Я часами пытался найти ответ или любую другую информацию, связанную со сравнением xstate и redux, или с некоторыми "за и против". К сожалению, у меня в голове беспорядок. Я не нашел какой-либо четкой информации, за исключением некоторых статей, таких как " переход от редукса к конечному автомату", или ссылок на библиотеки, ориентированные на совместное использование избыточности и xstate, и это, в конце концов, сломало меня.

Если кто-то может описать разницу или сказать мне, когда разработчики должны выбрать xstate - милости просим.

Спасибо.

3 ответа

Решение

Я создал XState, но я не собираюсь говорить вам, следует ли использовать один поверх другого; это зависит от вашей команды. Вместо этого я постараюсь выделить некоторые ключевые различия.

  • Redux - это, по сути, контейнер состояния, в котором события (называемые действиями в Redux) отправляются редуктору, который обновляет состояние.
  • XState также является контейнером состояний, но он разделяет конечное состояние (например, "loading", "success") из "бесконечного состояния" или контекста (например, items: [...]).
  • Redux не определяет, как вы определяете ваши редукторы. Это простые функции, которые возвращают следующее состояние, учитывая текущее состояние и событие (действие).
  • XState - это "редуктор с правилами" - вы определяете законные переходы между конечными состояниями из-за событий, а также какие действия должны выполняться при переходе (или при входе / выходе из состояния)
  • Redux не имеет встроенного способа обработки побочных эффектов. Есть много вариантов сообщества, таких как redux-thunk, redux-saga и т. Д.
  • XState делает действия (побочные эффекты) декларативными и явными - они являются частью State объект, который возвращается при каждом переходе (текущее состояние + событие).
  • Redux в настоящее время не имеет возможности визуализировать переходы между состояниями, поскольку он не различает конечное и бесконечное состояния.
  • XState имеет визуализатор: https://statecharts.github.io/xstate-viz который выполним благодаря декларативному характеру.
  • Неявная логика / поведение, представленное в редукторах Redux, не может быть декларативно сериализовано (например, в JSON)
  • Машинные определения XState, которые представляют логику / поведение, можно сериализовать в JSON и читать из JSON. Это делает поведение очень переносимым и настраиваемым внешними инструментами.
  • Redux не является конечным автоматом.
  • XState строго придерживается спецификации W3C SCXML: https://www.w3.org/TR/scxml/
  • Redux полагается на разработчика, чтобы вручную предотвратить невозможные состояния.
  • XState использует диаграммы состояний для естественного определения границ для обработки событий, что предотвращает невозможные состояния и может подвергаться статическому анализу.
  • Redux поощряет использование единого "глобального" атомарного магазина.
  • XState поощряет использование подхода, подобного модели актера, где может быть много экземпляров иерархической диаграммы состояний / "службы", которые взаимодействуют друг с другом.

Я добавлю больше ключевых отличий в документы на этой неделе.

Конечный автомат не сообщает (не заставляет) иметь однонаправленный поток данных. Это не имеет ничего общего с потоком данных. Это больше об ограничении изменений состояния и о переходах состояний. Таким образом, как правило, только некоторые части приложения будут создаваться с помощью конечных автоматов, и только в том случае, если вам нужно ограничить / запретить некоторые изменения состояния и вас интересуют переходы.

Имейте в виду, что для конечных автоматов, если по какой-то причине (зависимость от внешнего API и т. Д.) Существует вероятность того, что приложение может быть заблокировано в состоянии, когда оно не может перейти в другое состояние из-за ограничений, вы должны решить это.

Но если вас интересует только само последнее состояние приложения, а не переходы между состояниями, и ограничения состояния не имеют значения, то лучше не использовать конечный автомат и напрямую обновлять состояние (вы все еще можете переносить состояние в обновлении класса Singleton через Классы действий).


С другой стороны, Redux является структурой однонаправленной архитектуры. Однонаправленные архитектуры обеспечивают единую направленность потока данных. В Redux это начинается с User->View->(Action)->Store->Reducer->(Middleware)->Store->(State)->View, Подобно State Machines, вы можете запускать побочные эффекты с помощью Middlewares в Redux. Вы можете ограничить / запретить переходы состояний, если хотите. В отличие от State Machine, Redux обеспечивает однонаправленный поток данных, чистый! функции редуктора, неизменяемые объекты состояния, единое наблюдаемое состояние приложения.

несколько моих замечаний ниже.

  • Состояние пользовательского интерфейса и бизнес-состояние / состояние серверной части объединены в redux. Из-за этого каждое обновление пользовательского интерфейса или бизнес-состояния создает обновление данных в хранилище redux.

  • Xstate разделяет состояние пользовательского интерфейса и состояние серверной части.

  • В redux все узлы находятся внутри корневого узла. Xstate децентрализует и распределяет данные внутри независимых систем.

  • Приложение может только переходить между уже определенными состояниями. Так что любую ошибку или баг можно исправить в самом движке.

  • Внутренние состояния управляются самим движком в Xstate. Redux представляет новые состояния как флаги.

  • Агонист рендеринга - сохраняя как можно больше состояния, перенесенного в машины, и, если нам нужно, мы можем относительно легко переключить фреймворки рендеринга (например, с реакции на vue).

  • Contexts предоставляет конкретный класс для представления единого интерфейса для внешнего мира.
Другие вопросы по тегам