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

Отмена эффектов

Отмена эффектов в lite-fsm означает не остановку уже запущенной async-операции, а контроль над тем, какие transition-вызовы из effect всё ещё имеют право изменить состояние.

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

Проблема асинхронных эффектов

В приложениях, использующих асинхронные операции (HTTP-запросы, таймеры, загрузка данных), могут возникать случаи, когда:

  • Пользователь переходит на другую страницу до завершения запроса
  • Новый запрос инициируется до завершения предыдущего
  • Состояние автомата меняется, делая результат асинхронной операции неактуальным

В таких случаях нужно отделить выполнение async-кода от права этого кода отправить результат обратно в автомат.

Отмена через latest

По умолчанию при смене состояния автомата эффекты не отменяются автоматически. Отмена transition-вызовов из устаревшего запуска включается через createEffect({ type: "latest", ... }).

Важно: при отмене effect сам код уже запущенного effect продолжает выполняться. Отмена блокирует только transition-вызовы внутри устаревшего запуска:

import { createEffect, createMachine } from "@lite-fsm/core"; export const player = createMachine({ config: { IDLE: { CHANGE_TRACK: "LOAD_TRACK_DATA", }, LOAD_TRACK_DATA: { LOAD_TRACK_DATA_STARTED: "LOAD_TRACK_DATA_PENDING", }, LOAD_TRACK_DATA_PENDING: { LOAD_TRACK_DATA_RESOLVE: "SELECT_STREAM_PENDING", CHANGE_TRACK: "LOAD_TRACK_DATA", // Переход сюда НЕ отменит текущие эффекты по умолчанию }, SELECT_STREAM_PENDING: { SELECT_STREAM_RESOLVE: "SET_STREAM_PENDING", }, SET_STREAM_PENDING: {}, }, initialState: "IDLE", initialContext: {}, reducer: (state, _action, { nextState }) => { state.state = nextState; }, effects: { LOAD_TRACK_DATA: ({ transition }) => { transition({ type: "LOAD_TRACK_DATA_STARTED" }); }, LOAD_TRACK_DATA_PENDING: createEffect({ type: "latest", // включает игнорирование старых transition при перезапуске эффекта effect: async ({ transition }) => { // Здесь код продолжит выполняться даже после "отмены", // но вызовы transition из устаревшего запуска будут проигнорированы await someAsyncOperation(); transition({ type: "LOAD_TRACK_DATA_RESOLVE", }); }, }), }, });

В этом примере, если автомат находится в LOAD_TRACK_DATA_PENDING и приходит CHANGE_TRACK, transition-вызовы из прежнего запуска будут проигнорированы благодаря type: "latest". Без этой опции результаты всех запусков смогут отправлять события независимо от смены состояния.

Типы эффектов и стратегии отмены

lite-fsm поддерживает две стратегии для обёртки createEffect:

1. Тип “latest”

Право отправлять transition остаётся только у последнего запуска. Transition-вызовы из предыдущих запусков игнорируются:

const searchEffect = createEffect({ type: "latest", // включает игнорирование transition-вызовов из прежних запусков effect: async ({ action, api, transition }) => { const results = await api.search(action.payload.query); transition({ type: "SEARCH_RESOLVE", payload: { results } }); }, });

2. Тип “every”

Все запуски сохраняют право отправлять transition. Это поведение используется по умолчанию:

const logEffect = createEffect({ type: "every", // можно не указывать — это значение по умолчанию effect: async ({ action, analytics }) => { await analytics.logEvent(action); }, });
Last updated on