Глобальные эффекты
Глобальные эффекты в lite-fsm позволяют вынести резервную обработку событий в effect с ключом "*". Такой effect удобен для сквозной функциональности: логирования, аналитики или мониторинга состояния системы.
Концепция глобальных эффектов
Глобальный effect задаётся ключом "*" в объекте effects. Он запускается для обработанного события, если не был запущен более конкретный effect по имени нового state. При переходе без смены state конкретный state-effect не запускается, поэтому глобальный effect остаётся способом отреагировать на событие без смены состояния.
Создание глобальных эффектов
Для определения глобального эффекта используйте символ "*" в качестве ключа в объекте effects:
import { createMachine } from "@lite-fsm/core";
export const analytics = createMachine({
config: {
IDLE: {},
},
initialState: "IDLE",
initialContext: {},
effects: {
"*": ({ action, getState, ym }) => {
if (action.type === "LOGIN_RESOLVE") {
const userId = getState().session.context.userId ?? -1;
ym.reachGoal("auth", userId);
}
},
},
});
getStateи сервисymздесь — это пользовательские зависимости, которые мы передаём в менеджер черезsetDependencies({ getState: manager.getState, ym }). См. раздел Внедрение зависимостей.
Параметры глобальных эффектов
Глобальные эффекты получают те же параметры, что и обычные:
action— событие, которое привело к переходу;transition(action)— отправить новое событие;condition(predicate)— дождаться matching action;- любые пользовательские зависимости, переданные через
setDependencies.
effects: {
"*": ({ action, transition, logger, getState }) => {
console.log(`Action: ${action.type}`, action.payload);
console.log("Global state:", getState());
if (action.type === "CRITICAL_ERROR") {
logger.error("Critical error occurred", action.payload);
transition({ type: "SHOW_ERROR_DIALOG", payload: action.payload });
}
},
}Типичные сценарии использования
1. Отслеживание аналитики
Типичный сценарий для глобальных эффектов — отправка событий в систему аналитики:
const analyticsMachine = createMachine({
config: {
IDLE: {},
},
initialState: "IDLE",
initialContext: {},
effects: {
"*": ({ action, analytics, getState }) => {
try {
if (action.type.startsWith("__")) return;
const state = getState();
const userId = state.auth?.context?.userId;
const sessionId = state.session?.context?.id;
analytics.track({
eventName: action.type,
properties: {
...action.payload,
userId,
sessionId,
timestamp: new Date().toISOString(),
},
});
} catch (error) {
console.error("Analytics tracking error:", error);
}
},
},
});2. Логирование состояний и переходов
Глобальные эффекты подходят для реализации логирования:
const loggingMachine = createMachine({
config: {
IDLE: {},
},
initialState: "IDLE",
initialContext: {},
effects: {
"*": ({ action, getState }) => {
if (process.env.NODE_ENV === "development") {
const currentState = getState();
console.group(`📊 Action: ${action.type}`);
console.log("Payload:", action.payload);
console.log("Current State:", currentState);
console.groupEnd();
}
},
},
});3. Мониторинг ошибок
Отслеживание и обработка ошибок на уровне FSM-событий:
const errorMonitorMachine = createMachine({
config: {
IDLE: {},
},
initialState: "IDLE",
initialContext: {},
effects: {
"*": ({ action, errorMonitoring }) => {
if (action.type.includes("ERROR") && action.payload?.error) {
errorMonitoring.captureException(action.payload.error, {
tags: { actionType: action.type },
extra: { payload: action.payload },
});
}
},
},
});Лучшие практики
- Держите глобальные effects наблюдателями: они не должны незаметно менять основной поток событий.
- Обрабатывайте ошибки: Оборачивайте код глобальных эффектов в try-catch, чтобы ошибки не нарушали работу основного приложения.
- Используйте для сквозной функциональности: Аналитика, логирование и мониторинг — хорошие кандидаты для глобальных эффектов.
- Ограничивайте вызовы переходов: Будьте осторожны с вызовом
transitionв глобальных эффектах, чтобы избежать бесконечных циклов. - Разделяйте ответственность: выносите аналитику, логирование и мониторинг в отдельные машины, если они не принадлежат доменной машине.
- Ограничивайте работу по условию: выполняйте только нужные операции, чтобы глобальный effect не стал дорогой обработкой каждого события.