Прежде чем продолжить, я хотел бы указать, что название этого вопроса было довольно сложно сформулировать. Если нужно использовать более подходящее название, сообщите мне, чтобы я мог изменить его и сделать этот вопрос более полезным для других.
Хорошо, к проблеме... Я сейчас работаю над проектом React/Redux. Я принимал конструктивное решение, заключавшееся в том, чтобы управлять состоянием приложения и пользовательским интерфейсом почти полностью с (иерархическими) государственными машинами по ряду причин (которые я не буду вникать).
Я воспользовался Redux для хранения моего дерева состояний в store.machine
под названием store.machine
. Затем остальные подстанции Redux отвечают за хранение данных приложения. Таким образом, я выделил две проблемы, чтобы они не пересекали границы.
Исходя из этого, я также разделял проблемы на стороне (React) - используя "компоненты состояния" и "компоненты пользовательского интерфейса". Компоненты состояния почти полностью связаны с потоком состояния, а компоненты пользовательского интерфейса - это те компоненты, которые отображаются на экране.
У меня есть три типа компонентов состояния:
- Узел: этот государственный компонент имеет дело с ветвлением состояния. Он определяет, какой компонент должен быть создан на основе его текущего состояния (формы делегирования).
- Лист: эта форма состояния существует в листьях дерева состояний. Его задача состоит в том, чтобы отображать компонент пользовательского интерфейса, передавая необходимые "обратные вызовы", ответственные за обновление дерева состояний.
- Контейнер: этот компонент состояния инкапсулирует компонент узла и интерфейса, который будет отображаться бок о бок.
Для моих обстоятельств нас интересуют только узловые и листовые компоненты. Проблема, с которой я сталкиваюсь, заключается в том, что, хотя компоненты пользовательского интерфейса визуализируются на основе "состояний листа", могут быть сценарии, в которых состояния более высокого уровня могут влиять на то, как должен отображаться пользовательский интерфейс.
Возьмите эту упрощенную государственную структуру:
AppState
начинается в состоянии " Home
. Когда пользователь нажимает кнопку входа в систему, to_login
действие to_login
. Редуктор, AppState
управлять AppState
, получит это действие и установит новое текущее состояние для Login
в Login
.
Аналогично, после того, как пользователь наберет свои учетные данные и проведет проверку, будет отправлено либо success
либо fail
действие. Опять же, это получает тот же редуктор, который затем переходит к соответствующему состоянию: User_Portal
или Login_Failed
.
Структура компонента React будет выглядеть примерно так:
Наш узел верхнего уровня получает AppState
в качестве опоры, проверяет текущее состояние и отображает/делегирует один из компонентов дочернего листа.
Затем компоненты "Лист" отображают конкретные компоненты пользовательского интерфейса, проходящие по обратным вызовам, чтобы позволить им отправлять необходимые действия (описанные выше) для обновления состояния. Пунктирная линия представляет границу между "состоянием" и "ui", и эта граница пересекается только на компонентах Листа. Это позволяет работать независимо от штата и пользовательского интерфейса, и поэтому я хочу что-то поддерживать.
Здесь все становится сложным. Представьте себе, что для аргументации у нас есть состояние верхнего уровня для описания языка, на котором находится приложение, - скажем, на English
и French
. Наша обновленная структура компонентов может выглядеть так:
Теперь наши компоненты пользовательского интерфейса должны отображаться на правильном языке, хотя состояние, описывающее это, не является листом. Компоненты Leaf, которые имеют отношение к отображению пользовательского интерфейса, не имеют понятия о родительских состояниях и, следовательно, не содержат понятия языка, в котором находится приложение. И, таким образом, состояние языка нельзя безопасно передать в пользовательский интерфейс без нарушения модели. Либо можно будет удалить граничную линию состояния/интерфейса, или родительское состояние должно быть передано детям, оба из которых являются ужасными решениями.
Одним из решений является "копировать" AppState
дерева AppState
для каждого языка, по существу создавая целую новую древовидную структуру на язык... например:
Это почти так же плохое решение, как и два описанных выше, и для управления вещами потребуется увеличение количества компонентов.
Более подходящее решение (по крайней мере, когда речь идет о чем-то вроде языков) заключается в том, чтобы воздерживаться от использования его как "состояния" и вместо этого хранить некоторые "данные" об этом. Затем каждый компонент может посмотреть на эти данные (либо значение currentLanguage
либо список сообщений, предварительно переведенных на этом языке), чтобы правильно отображать вещи.
Эта проблема "языков" не очень хороший пример, потому что ее можно легко структурировать как "данные", а не "состояние". Но это послужило способом продемонстрировать мою загадку. Возможно, лучшим примером является экзамен, который может быть приостановлен. Давайте посмотрим:
Представьте себе, что у экзамена два вопроса. Когда в состоянии "приостановлено" текущий вопрос отключается (т.е. Взаимодействие с пользователем не может быть выполнено). Как вы можете видеть выше, нам нужно "дублировать" листья для каждого вопроса в разделе " Playing
и " Paused
чтобы можно было передать правильное состояние - что-то нежелательное из-за причин, о которых я упоминал ранее.
Опять же, мы могли бы хранить логическое значение где-то, что описывает состояние экзамена - то, что могут выполнить опросы компонентов UI (Q1 и Q2). Но, в отличие от примера "Языки", это логическое значение - это "состояние", а не часть "данных". И поэтому, в отличие от языков, этот сценарий требует, чтобы это состояние хранилось в дереве состояний.
Именно такой сценарий меня озадачил. Какие решения или варианты у меня есть, что может позволить мне передать мои вопросы при использовании информации о состоянии нашего приложения, которое не содержится в Листе?
Изменить: приведенные выше примеры используют FSM. В моей заявке я создал еще несколько достижений государственных машин:
- MSM (многогосударственный автомат): контейнер для нескольких состояний, которые активны одновременно
- DSM (динамический конечный автомат): FSM, который настраивается во время выполнения
- DMSM (динамическая многостанционная машина): МСМ, который настраивается во время выполнения
Если любой из этих типов государственных машин может помочь решить проблему, пожалуйста, сообщите мне об этом.
Любая помощь высоко ценится!
@JonasW. Вот структура, использующая МСМ:
Такая структура до сих пор не позволила мне получить "правдоподобную" информацию о состоянии на вопросы.