Интеграция с React
Библиотека lite-fsm предоставляет готовые компоненты и хуки для простой интеграции с React приложениями.
Установка
Для использования модуля React с lite-fsm вам не нужно устанавливать дополнительные пакеты, так как он уже включен в основную библиотеку:
npm install lite-fsmДоступ к модулю React
import { FSMContextProvider, useSelector, useTransition } from "lite-fsm/react";Совет: Если вы используете TypeScript, рекомендуется создать строготипизированные версии хуков, как показано в разделе TypeScript. Это обеспечит автодополнение и проверку типов во время компиляции, что значительно снизит количество потенциальных ошибок.
Основные компоненты и хуки
FSMContextProvider
FSMContextProvider — компонент-провайдер, который предоставляет доступ к менеджеру автоматов для всех дочерних компонентов через React Context.
import { createMachine, MachineManager, type FSMEvent } from "lite-fsm";
import { FSMContextProvider } from "lite-fsm/react";
export type Events = FSMEvent<"INCREMENT"> | FSMEvent<"DECREMENT"> | FSMEvent<"RESET">;
// Создаем автомат
const counterMachine = createMachine({
config: {
IDLE: {
INCREMENT: null,
DECREMENT: null,
RESET: null,
},
},
initialState: "IDLE",
initialContext: {
count: 0,
},
reducer: (state, action) => {
switch (action.type) {
case "INCREMENT":
state.context.count++;
break;
case "DECREMENT":
state.context.count--;
break;
case "RESET":
state.context.count = 0;
break;
}
},
});
// Создаем менеджер
const manager = MachineManager({
counter: counterMachine,
});
// Использование в корне приложения
function App() {
return (
<FSMContextProvider machineManager={manager}>
<Counter />
</FSMContextProvider>
);
}useSelector
Хук useSelector позволяет выбирать и подписываться на состояние из менеджера автоматов:
import { useSelector, useTransition } from "lite-fsm/react";
function Counter() {
// Получаем значение count из контекста автомата counter
const count = useSelector((state) => state.counter.context.count);
// Альтернативный способ: получить всё состояние автомата
const { state, context } = useSelector((state) => state.counter);
// Получить состояние нескольких автоматов
const { counterValue, authState } = useSelector((state) => ({
counterValue: state.counter.context.count,
authState: state.auth.state,
}));
return (
<div>
<h2>Счетчик: {count}</h2>
{/* ... */}
</div>
);
}useTransition
Хук useTransition предоставляет функцию для отправки событий автоматам:
import { useSelector, useTransition } from "lite-fsm/react";
function Counter() {
const count = useSelector((state) => state.counter.context.count);
const transition = useTransition();
return (
<div>
<h2>Счетчик: {count}</h2>
<button onClick={() => transition({ type: "INCREMENT" })}>Увеличить</button>
<button onClick={() => transition({ type: "DECREMENT" })}>Уменьшить</button>
<button onClick={() => transition({ type: "RESET" })}>Сбросить</button>
</div>
);
}useManager
Хук useManager даёт прямой доступ к объекту менеджера автоматов:
import { useManager } from "lite-fsm/react";
function DebugPanel() {
const manager = useManager();
// Получаем полное состояние всех автоматов
const state = manager.getState();
// Можем также подписаться на изменения
useEffect(() => {
const unsubscribe = manager.onTransition((prevState, nextState, action) => {
console.log("Transition:", { prevState, nextState, action });
});
return unsubscribe;
}, [manager]);
return (
<div className="debug-panel">
<pre>{JSON.stringify(state, null, 2)}</pre>
</div>
);
}Практические примеры
Авторизация пользователя
const initialContext = {
user: null,
error: null,
username: "",
password: "",
};
// Создание автомата
const authMachine = createMachine({
config: {
LOGGED_OUT: {
LOGIN: "LOGGING_IN",
UPDATE_CREDENTIALS: null, // Обновление username/password остается в том же состоянии
},
LOGGING_IN: {
LOGIN_SUCCESS: "LOGGED_IN",
LOGIN_ERROR: "LOGIN_ERROR",
},
LOGGED_IN: {
LOGOUT: "LOGGED_OUT",
},
LOGIN_ERROR: {
LOGIN: "LOGGING_IN",
RESET: "LOGGED_OUT",
UPDATE_CREDENTIALS: null, // Обновление данных в состоянии ошибки
},
},
initialState: "LOGGED_OUT",
initialContext,
reducer: (state, action) => {
switch (action.type) {
case "UPDATE_CREDENTIALS":
state.context = {
...state.context,
...action.payload,
};
break;
case "LOGOUT":
case "RESET":
state.context = initialContext;
break;
}
},
effects: {
LOGGING_IN: async ({ transition, services, getState }) => {
try {
// Получаем данные из контекста автомата вместо payload
const { username, password } = getState().auth.context;
const user = await services.authService.login(username, password);
transition({ type: "LOGIN_SUCCESS", payload: { user } });
} catch (error) {
transition({
type: "LOGIN_ERROR",
payload: { error: error.message },
});
}
},
LOGGED_IN: ({ services }) => {
services.analyticsService.trackEvent("user_login");
},
},
});
// Компонент формы входа
function LoginForm() {
const { state, context } = useSelector((state) => state.auth);
const transition = useTransition();
// Получаем данные из контекста автомата вместо локального состояния
const { username, password, error } = context;
// Обработчики изменения полей ввода
const handleUsernameChange = (e) => {
transition({
type: "UPDATE_CREDENTIALS",
payload: { username: e.target.value },
});
};
const handlePasswordChange = (e) => {
transition({
type: "UPDATE_CREDENTIALS",
payload: { password: e.target.value },
});
};
const handleSubmit = (e) => {
e.preventDefault();
transition({ type: "LOGIN" });
};
return (
<form onSubmit={handleSubmit}>
{error && <div className="error">{error}</div>}
<div>
<label>Имя пользователя:</label>
<input type="text" value={username} onChange={handleUsernameChange} />
</div>
<div>
<label>Пароль:</label>
<input type="password" value={password} onChange={handlePasswordChange} />
</div>
<button type="submit" disabled={state === "LOGGING_IN"}>
{state === "LOGGING_IN" ? "Вход..." : "Войти"}
</button>
</form>
);
}Заключение
Интеграция lite-fsm с React предоставляет удобный и предсказуемый способ управления состоянием приложения. Используя хуки и компоненты из модуля lite-fsm/react, вы можете легко подключить конечные автоматы к вашим React компонентам и получить все преимущества управления состоянием на основе конечных автоматов.