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

API Справочник

В этом разделе приведена документация по всем функциям и типам библиотеки lite-fsm.

Основной модуль

Основной модуль предоставляет функции для создания и управления конечными автоматами.

createMachine

createMachine<C, T, E, P = FSMEvent<E, any>, D = {}>(cfg: MachineConfig<C, T, P, D>): Machine<C, T, P, D>

Функция для создания конечного автомата.

Параметры:

  • cfg: Объект конфигурации автомата.

Возвращает:

Объект автомата.

Пример:

import { createMachine } from "lite-fsm"; const toggleMachine = createMachine({ config: { INACTIVE: { TOGGLE: "ACTIVE", }, ACTIVE: { TOGGLE: "INACTIVE", }, }, initialState: "INACTIVE", initialContext: { lastToggled: null, }, });

MachineManager

MachineManager<M extends Record<string, Machine<any, any, any, any>>>( machines: M, opts?: { middleware?: Middleware<MachinesState<M>, any>[]; onError?: (err: any) => void; } ): MachineManager<M>

Функция для создания менеджера автоматов.

Параметры:

  • machines: Объект с автоматами, где ключи - имена автоматов, а значения - объекты автоматов.
  • opts: (Опционально) Объект с дополнительными опциями.
    • middleware: Массив функций middleware для расширения функциональности.
    • onError: Обработчик ошибок, возникающих при выполнении эффектов.

Возвращает:

Менеджер автоматов.

Пример:

import { MachineManager, createMachine } from "lite-fsm"; import { immerMiddleware } from "lite-fsm/middleware"; const toggleMachine = createMachine({ // ...конфигурация }); const counterMachine = createMachine({ // ...конфигурация }); // Создание менеджера без дополнительных опций const simpleManager = MachineManager({ toggle: toggleMachine, counter: counterMachine, }); // Создание менеджера с middleware и обработчиком ошибок const advancedManager = MachineManager( { toggle: toggleMachine, counter: counterMachine, }, { middleware: [ immerMiddleware, // Пользовательский middleware для логирования (api) => (next) => (action) => { console.log("Action:", action); const result = next(action); console.log("New state:", api.getState()); return result; }, ], onError: (error) => { console.error("Error in machine effect:", error); // Можно отправить ошибку в сервис мониторинга }, }, );

Методы MachineManager

transition
transition<E extends string, P extends Record<string, any>>( action: { type: E; payload?: P } ): void

Выполняет переход состояния для всех автоматов.

Параметры:

  • action: Объект действия.
    • type: Тип события.
    • payload: (Опционально) Полезная нагрузка, которая будет доступна в редьюсерах и эффектах.

Пример:

// Отправить событие с payload manager.transition({ type: "TOGGLE", payload: { lastToggled: new Date() }, }); // Отправить событие без payload manager.transition({ type: "RESET" });
getState
getState(): { [K in keyof M]: { state: State<C>; context: T } }

Возвращает текущее состояние и контекст всех автоматов.

Возвращает:

Объект, в котором ключи - имена автоматов, а значения - объекты с состоянием и контекстом.

Пример:

const state = manager.getState(); console.log(state.toggle.state); // Текущее состояние автомата toggle console.log(state.counter.context); // Текущий контекст автомата counter
onTransition
onTransition( callback: ( prevState: { [K in keyof M]: { state: State<C>; context: T } }, nextState: { [K in keyof M]: { state: State<C>; context: T } }, action: { type: string; payload?: any } ) => void ): () => void

Подписывает функцию на события перехода состояний.

Параметры:

  • callback: Функция обратного вызова, которая будет вызываться при каждом переходе состояния.

Возвращает:

Функция для отмены подписки.

Пример:

const unsubscribe = manager.onTransition((prevState, nextState, action) => { console.log("Предыдущее состояние:", prevState); console.log("Новое состояние:", nextState); console.log("Действие:", action); }); // Позже, когда подписка больше не нужна unsubscribe();
setDependencies
setDependencies<D extends Record<string, any> = {}>(dependencies: D | ((deps: D) => D)): void

Устанавливает зависимости, которые будут доступны в эффектах. Можно передать либо объект с зависимостями, либо функцию обновления, которая получает текущие зависимости и возвращает новые.

Параметры:

  • dependencies: Объект с зависимостями или функция, принимающая текущие зависимости и возвращающая новые.

Пример объекта:

// Установка зависимостей напрямую через объект manager.setDependencies({ services: { api: { fetchData: async () => { const response = await fetch("/api/data"); return response.json(); }, }, storage: { saveItem: (key, value) => localStorage.setItem(key, JSON.stringify(value)), getItem: (key) => JSON.parse(localStorage.getItem(key) || "null"), }, }, utils: { formatDate: (date) => new Intl.DateTimeFormat().format(date), generateId: () => Math.random().toString(36).substring(2), }, });

Пример функции обновления:

// Обновление существующих зависимостей с сохранением предыдущих значений manager.setDependencies((prevDeps) => ({ ...prevDeps, services: { ...prevDeps.services, analytics: { trackEvent: (eventName, params) => { console.log(`Analytics event: ${eventName}`, params); // Отправка события в аналитику }, }, }, // Добавление новых зависимостей env: { isDevelopment: process.env.NODE_ENV === "development", apiUrl: process.env.API_URL, }, }));

Функциональный подход особенно полезен для поэтапного обновления зависимостей или для добавления новых зависимостей без потери существующих.

replaceReducer
replaceReducer( callback: ( reducer: (state: MachinesState<M>, action: A) => MachinesState<M> ) => (state: MachinesState<M>, action: A) => MachinesState<M> ): void

Заменяет редьюсер менеджера автоматов. Этот метод используется middleware для модификации поведения обработки состояний.

Параметры:

  • callback: Функция, которая принимает текущий редьюсер и возвращает новый редьюсер.

Пример:

// Пример создания middleware с использованием replaceReducer const loggingMiddleware = (api) => { // Заменяем редьюсер, добавляя логирование api.replaceReducer((reducer) => { return (state, action) => { console.log("Предыдущее состояние:", state); console.log("Действие:", action); const result = reducer(state, action); console.log("Новое состояние:", result); return result; }; }); return (next) => (action) => next(action); }; // Использование middleware const manager = MachineManager({ counter: counterMachine }, { middleware: [loggingMiddleware] });
condition
condition( predicate: (action: A) => boolean ): Promise<boolean>

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

Параметры:

  • predicate: Функция, которая принимает действие и возвращает булево значение.

Возвращает:

Промис, который резолвится со значением true, когда предикат возвращает true для какого-либо действия.

Пример:

// Использование condition в эффекте const machine = createMachine({ config: { IDLE: { START: "PROCESSING", }, PROCESSING: { SUCCESS: "SUCCESS", ERROR: "ERROR", }, SUCCESS: { RESET: "IDLE", }, ERROR: { RETRY: "PROCESSING", RESET: "IDLE", }, }, effects: { PROCESSING: async ({ transition, condition }) => { try { // Запуск асинхронной операции const processPromise = startLongProcess(); // Ожидание действия CANCEL до завершения операции const raceResult = await Promise.race([ processPromise, condition((action) => action.type === "CANCEL").then(() => ({ cancelled: true })), ]); // Если операция была отменена if (raceResult?.cancelled) { transition({ type: "ERROR", payload: { error: "Operation cancelled" } }); return; } // Если операция завершилась успешно transition({ type: "SUCCESS", payload: { result: raceResult } }); } catch (error) { transition({ type: "ERROR", payload: { error: error.message } }); } }, }, });

createConfig

createConfig<C extends Record<string, Record<string, string | null>>>( config: C ): C

Функция для создания и типизации конфигурации автомата.

Параметры:

  • config: Объект конфигурации автомата.

Возвращает:

Тот же объект конфигурации, но с правильной типизацией.

Пример:

import { createConfig, createMachine } from "lite-fsm"; const config = createConfig({ IDLE: { START: "RUNNING", }, RUNNING: { PAUSE: "PAUSED", STOP: "IDLE", }, PAUSED: { RESUME: "RUNNING", STOP: "IDLE", }, }); const machine = createMachine({ config, initialState: "IDLE", // ... });

createReducer

createReducer<C, T, P>( reducer: ( state: { state: State<C>; context: T }, action: P, options: { nextState: State<C> | null; config: C } ) => { state: State<C>; context: T } ): typeof reducer

Функция для создания и типизации пользовательского редьюсера.

Параметры:

  • reducer: Функция редьюсера.

Возвращает:

Тот же редьюсер, но с правильной типизацией.

Пример:

import { createReducer, createMachine } from "lite-fsm"; const reducer = createReducer((state, action, options) => { const { state: currentState, context } = state; const nextState = options.nextState || currentState; switch (action.type) { case "INCREMENT": return { state: nextState, context: { ...context, count: context.count + 1, }, }; case "DECREMENT": return { state: nextState, context: { ...context, count: context.count - 1, }, }; default: return { state: nextState, context: { ...context, ...(action.payload || {}), }, }; } }); const machine = createMachine({ config: { // ... }, reducer, // ... });

createEffect

createEffect<D extends DefaultDeps<any, any, any>, P extends Record<string, any> = {}>( opts: { type?: EffectType; effect: MachineEffect<D, P>; cancelFn?: (deps: D) => () => boolean; } ): (deps: D, payload: P) => any

Функция для создания эффекта с возможностью отмены.

Параметры:

  • opts: Объект с опциями.
    • type: (Опционально) Тип эффекта. Может принимать следующие значения:
      • "every": (по умолчанию) Выполняет каждый вызов эффекта независимо от других вызовов.
      • "latest": Игнорирует вызовы transition из предыдущих вызовов эффекта при новом вызове. Важно понимать, что код эффекта продолжает выполняться, но вызовы transition из устаревших эффектов будут проигнорированы. Это позволяет избежать состояния гонки (race condition) в асинхронных операциях, например, при поиске или загрузке данных, когда важно обрабатывать только результат последнего запроса.
    • effect: Функция эффекта.
    • cancelFn: (Опционально) Функция, которая возвращает функцию проверки условия отмены. Позволяет реализовать пользовательскую логику отмены эффекта.

Возвращает:

Функция эффекта с обработкой отмены.

Пример:

import { createEffect, createMachine } from "lite-fsm"; const searchMachine = createMachine({ config: { IDLE: { SEARCH: "SEARCHING", }, SEARCHING: { SEARCH_SUCCESS: "RESULTS", SEARCH_ERROR: "ERROR", }, RESULTS: { SEARCH: "SEARCHING", }, ERROR: { SEARCH: "SEARCHING", }, }, initialState: "IDLE", initialContext: { query: "", results: [], error: null, isLoading: false, }, effects: { SEARCHING: createEffect({ type: "latest", // Обрабатывать только результаты последнего поискового запроса effect: async ({ transition, services, action }) => { try { const query = action.payload?.query || ""; const results = await services.api.search(query); // Этот transition будет проигнорирован, если был сделан более новый запрос transition({ type: "SEARCH_SUCCESS", payload: { results }, }); } catch (error) { // Этот transition тоже будет проигнорирован для устаревших запросов transition({ type: "SEARCH_ERROR", payload: { error: error.message }, }); } }, }), }, });

Wildcard

Специальный символ "*" используется для обозначения состояния или события, которое должно соответствовать любому значению.

Пример:

import { createMachine } from "lite-fsm"; const machine = createMachine({ config: { IDLE: { START: "RUNNING", }, RUNNING: { STOP: "IDLE", }, // Обработка RESET из любого состояния "*": { RESET: "IDLE", }, }, // ... });

React API

Библиотека lite-fsm предоставляет интеграцию с React через набор компонентов и хуков.

FSMContextProvider

<FSMContextProvider machineManager={manager}>{children}</FSMContextProvider>

Компонент-провайдер, который делает менеджер автоматов доступным для всех дочерних компонентов через React Context.

Свойства:

  • machineManager: Объект менеджера автоматов, созданный с помощью MachineManager.
  • children: Дочерние компоненты.

Пример:

import { FSMContextProvider } from "lite-fsm/react"; import { MachineManager, createMachine } from "lite-fsm"; // Создание автомата const counterMachine = createMachine({ config: { IDLE: { INCREMENT: null, DECREMENT: null, RESET: null }, }, initialState: "IDLE", initialContext: { count: 0 }, // ... }); // Создание менеджера const manager = MachineManager({ counter: counterMachine, }); // Использование в приложении function App() { return ( <FSMContextProvider machineManager={manager}> <Counter /> <Controls /> </FSMContextProvider> ); }

useSelector

useSelector<R>( selector: (state: MachinesState<S>) => R, equalityFn?: (oldValue: R, newValue: R) => boolean ): R

Хук для выбора и подписки на часть состояния из менеджера автоматов.

Параметры:

  • selector: Функция, которая принимает состояние всех автоматов и возвращает производную часть этого состояния.
  • equalityFn: (Опционально) Функция сравнения для определения, изменилось ли выбранное состояние.

Возвращает: Выбранную часть состояния.

Пример:

import { useSelector } from "lite-fsm/react"; function Counter() { // Получение значения счетчика const count = useSelector((state) => state.counter.context.count); // Получение нескольких значений с мемоизацией const { isResettable, isDecrementable } = useSelector((state) => { const count = state.counter.context.count; return { isResettable: count > 0, isDecrementable: count > 0, }; }); return ( <div> <h2>Count: {count}</h2> <p>Can reset: {isResettable ? "Yes" : "No"}</p> <p>Can decrement: {isDecrementable ? "Yes" : "No"}</p> </div> ); }

useTransition

useTransition<P extends FSMEvent<any, any> = any>(): (action: P) => void

Хук, который возвращает функцию для отправки действий менеджеру автоматов.

Возвращает: Функция для отправки действий.

Пример:

import { useSelector, useTransition } from "lite-fsm/react"; function CounterControls() { const count = useSelector((state) => state.counter.context.count); const transition = useTransition(); return ( <div> <button onClick={() => transition({ type: "INCREMENT" })}>Increment</button> <button onClick={() => transition({ type: "DECREMENT" })} disabled={count <= 0}> Decrement </button> <button onClick={() => transition({ type: "RESET" })} disabled={count === 0}> Reset </button> </div> ); }

useManager

useManager<S extends Record<string, MachineConfig<any, any, any, any>>>(): MachineManager<S>

Хук для получения прямого доступа к объекту менеджера автоматов.

Возвращает: Объект менеджера автоматов.

Пример:

import { useManager } from "lite-fsm/react"; import { useEffect } from "react"; function Debug() { const manager = useManager(); // Получение полного состояния всех автоматов const state = manager.getState(); useEffect(() => { // Подписка на все изменения состояния const unsubscribe = manager.onTransition((prevState, nextState, action) => { console.log("Действие:", action); console.log("Предыдущее состояние:", prevState); console.log("Новое состояние:", nextState); }); return unsubscribe; }, [manager]); return ( <div> <h3>Текущее состояние:</h3> <pre>{JSON.stringify(state, null, 2)}</pre> <button onClick={() => manager.transition({ type: "RESET_ALL" })}>Сбросить все</button> </div> ); }
Last updated on