Skip to Content
👋 Добро пожаловать в документацию lite-fsm!

Глобальные переходы

Глобальные переходы позволяют определить события, которые могут обрабатываться независимо от текущего состояния автомата. Они подходят для общих событий: ошибок, сброса состояния или действий пользователя, доступных из любой точки процесса.

Примеры reducer-ов на этой странице написаны в стиле Immer: они мутируют draft state и предполагают, что MachineManager создан с immerMiddleware. Без middleware reducer должен вернуть новый объект { state, context }.

Концепция глобальных переходов

В lite-fsm глобальные переходы задаются ключом "*". Такой переход используется как резервный вариант, если в текущем состоянии нет перехода для того же события.

Синтаксис определения глобальных переходов

Глобальные переходы определяются в конфигурации автомата с использованием символа "*" в качестве ключа:

import { createMachine } from "@lite-fsm/core"; export const player = createMachine({ config: { "*": { CHANGE_TRACK: "LOAD_TRACK_DATA_PENDING", }, IDLE: {}, LOAD_TRACK_DATA_PENDING: {}, SELECT_STREAM_PENDING: {}, SET_STREAM_PENDING: {}, }, initialState: "IDLE", initialContext: {}, reducer: (state, _action, { nextState }) => { state.state = nextState; }, });

Приоритет переходов

При обработке событий lite-fsm проверяет переходы в следующем порядке:

  1. Специфичные переходы для текущего состояния
  2. Глобальные переходы (если специфичный переход не определен)

Это означает, что глобальные переходы могут быть переопределены в конкретных состояниях:

config: { "*": { RESET: "IDLE", // Применяется ко всем состояниям ERROR: "ERROR_STATE", // Применяется ко всем состояниям, кроме тех, где переопределено }, PLAYING: { ERROR: "PLAYING_ERROR", // Переопределяет глобальный переход для состояния PLAYING }, }

Применение глобальных переходов

1. Общие действия, доступные в любом состоянии

const player = createMachine({ config: { "*": { CHANGE_TRACK: "PAUSED", }, PAUSED: { RESUME: "PLAYING", }, PLAYING: { PAUSE: "PAUSED", }, }, initialState: "PAUSED", initialContext: {}, });

2. Обработка ошибок на глобальном уровне

const app = createMachine({ config: { "*": { NETWORK_ERROR: "ERROR", FATAL_ERROR: "CRASHED", }, IDLE: { FETCH_DATA: "LOADING", }, LOADING: { DATA_LOADED: "DATA_READY", }, DATA_READY: { PROCESS_DATA: "PROCESSING", }, PROCESSING: {}, ERROR: {}, CRASHED: {}, }, initialState: "IDLE", initialContext: {}, });

3. Сброс состояния

const form = createMachine({ config: { "*": { RESET_FORM: "INITIAL", // Сброс формы из любого состояния }, INITIAL: { FIELD_CHANGE: "EDITING", }, EDITING: { SUBMIT: "VALIDATING", }, VALIDATING: { VALIDATION_SUCCESS: "SUBMITTING", VALIDATION_ERROR: "INVALID", }, INVALID: { FIELD_CHANGE: "EDITING", }, SUBMITTING: { SUBMIT_SUCCESS: "SUCCESS", SUBMIT_ERROR: "ERROR", }, SUCCESS: {}, ERROR: { RETRY: "SUBMITTING", }, }, initialState: "INITIAL", initialContext: {}, });

Лучшие практики

  1. Используйте для общих операций: Глобальные переходы подходят для действий, которые должны быть доступны из любого состояния.
  2. Избегайте избыточности: Не дублируйте один и тот же переход во всех состояниях, используйте глобальный переход.
  3. Переопределяйте где нужно: В состояниях, где поведение должно отличаться, переопределите глобальный переход.
  4. Документируйте глобальные события: явно указывайте, какие события обрабатываются глобально, чтобы поведение оставалось проверяемым.
  5. Используйте для отладки: Глобальные переходы удобны для добавления отладочных действий во время разработки.
  6. Ограничивайте область применения: слишком много глобальных переходов усложняет чтение графа. Чаще всего они уместны для сброса, отмены или критических ошибок.
Last updated on