Cuando construyes formularios por pasos o flujos con varias vistas en React, necesitas una forma clara de controlar qué se muestra y cuándo. Ahí entran las máquinas de estados: un modelo que representa un sistema con múltiples estados y define cómo moverte entre ellos según las acciones del usuario.
Esta guía te muestra cómo modelar una máquina de estados en React con TypeScript usando un formulario wizard de tres pasos como caso real.
Cómo funciona una máquina de estados en desarrollo web
Imagina tu aplicación con tres estados: estado uno, estado dos y estado tres. Solo uno se visualiza a la vez; los demás están ocultos. Para pasar de un estado al siguiente necesitas una transición, y esa transición puede tener blockers que impiden avanzar si no se cumple cierta condición.
Un formulario wizard es el ejemplo perfecto. El primer paso pide el nombre, el segundo pide la edad y el tercero confirma los datos. Para avanzar del paso uno al dos, todos los campos del formulario deben estar llenos. Esa validación es justo la acción que dispara la transición.
¿Qué es una máquina de estados? Es un modelo que define los estados posibles de un sistema y las reglas para transitar entre ellos. En React te sirve para controlar flujos como formularios por pasos, asistentes o procesos de checkout.
Cómo configurar el proyecto con Vite y React TypeScript
Arranca un proyecto desde cero con Vite. En la terminal corre npm create vite@latest, nómbralo my-state-machine-app y elige React + TypeScript como stack. Entra a la carpeta y ejecuta npm install para instalar dependencias.
Una vez levantado el servidor, abre el archivo App y borra el contenido de plantilla. Vas a empezar limpio para definir la estructura de la máquina.
Cómo definir la interfaz StateMachineConfig en TypeScript
La configuración de la máquina necesita tres piezas: un paso inicial, los pasos disponibles y las vistas que se renderizan en cada uno. Esto se modela con una interface en TypeScript.
ts
interface StateMachineConfig<StateType, StepNames extends string> {
initialStep: StepNames;
steps: {
[key in StepNames]: {
advance: (state: StateType) => boolean;
};
};
views: {
[key in StepNames]: React.ComponentType<{
state: StateType;
setState: React.Dispatch<React.SetStateAction<StateType>>;
}>;
};
}
Por qué necesitas un initialStep
El initialStep le dice a la máquina qué vista mostrar primero. En el ejemplo del wizard, ese paso inicial es el formulario que pregunta el nombre. Sin esta propiedad la máquina no sabría dónde arrancar.
Cómo funciona la propiedad advance en cada step
Cada step incluye una función advance que retorna un boolean. Si retorna true, el usuario puede pasar al siguiente estado; si retorna false, queda bloqueado. Esta función recibe el estado actual y evalúa si la información está completa.
Por ejemplo, en el paso uno advance revisa que el campo nombre no esté vacío. En el paso dos verifica que la edad tenga un valor numérico válido.
Qué rol cumplen las views dentro de la máquina
Las views son los componentes de React que se renderizan en cada paso. Cada vista recibe dos props: el estado actual (state) para leer la información y setState para modificarla. Así, leer y escribir el estado queda centralizado.
Cómo tipar los pasos con StepNames y WizardState
Para que TypeScript te ayude a detectar errores, define un tipo con los nombres de los pasos y otro con la forma del estado del formulario.
ts
type StepNames = 'step1' | 'step2' | 'confirmation';
type WizardState = {
name: string;
age: number;
};
El tipo StepNames restringe las claves de steps y views a esos tres valores exactos. Si intentas registrar un paso con otro nombre, TypeScript te avisa. El tipo WizardState describe los datos que captura el formulario: un nombre como string y una edad numérica.
¿Por qué usar TypeScript en máquinas de estados? Porque garantiza que cada paso tenga su vista, su lógica de avance y su tipo de estado correcto. Reduce errores de runtime y hace el código autodocumentado.
Cómo se conectan los tipos genéricos en la configuración
La interface usa dos genéricos: StateType y StepNames extends string. StateType representa la forma del estado completo del wizard y StepNames es la unión de claves válidas. Al combinar ambos, cada vista recibe el tipo correcto de state y setState sin necesidad de duplicar declaraciones.
Esta es la base estructural. Con los tipos listos, ya puedes registrar los componentes que renderizan cada paso y la lógica que decide cuándo avanzar.
¿Has trabajado antes con formularios wizard en React? Cuéntame en los comentarios qué patrón usas para manejar los pasos.