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

Интеграция с 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 компонентам и получить все преимущества управления состоянием на основе конечных автоматов.

Last updated on