Contenido del curso

Patrones de renderizado y composición

Manejo del estado en React

Componente wizard con máquina de estados en React

Resumen

Construir un formulario tipo wizard en React se vuelve mucho más limpio cuando lo conectas a una máquina de estados. Aquí aprenderás a crear el componente StateMachineWizard, manejar estados locales con useState y renderizar vistas dinámicas según el paso actual, todo con TypeScript y tipos genéricos.

Esta guía es para desarrolladores frontend que ya tienen una configuración base de máquina de estados y quieren conectarla a la interfaz para mover al usuario entre pasos como nombre, edad y confirmación.

Cómo defines los estados locales del wizard en React

El componente StateMachineWizard arranca desde cero, eliminando el contenido por defecto del proyecto. Lo primero que necesitas son dos estados locales que trabajen en conjunto: uno guarda los datos del formulario y otro controla el paso visible.

El estado wizardState almacena la información que el usuario va completando, como el nombre y la edad inicializada en cero. Por su parte, currentStep lleva el control de en qué pantalla del wizard estás parado.

tsx const [wizardState, setWizardState] = useState<WizardState>({ name: '', age: 0, });

const [currentStep, setCurrentStep] = useState<StepName>( stateMachineConfig.initialStep );

El valor inicial de currentStep no se inventa: se toma directamente de stateMachineConfig.initialStep, lo que mantiene la fuente de verdad en la configuración de la máquina [01:45].

¿Por qué usar dos estados separados en un wizard? Porque tienen responsabilidades distintas: wizardState guarda los datos que el usuario ingresa, mientras currentStep solo indica qué vista renderizar. Separarlos evita re-renders innecesarios y facilita validar avances.

Cómo renderizar la vista correcta según el paso actual

La configuración de la máquina expone un objeto views donde cada key corresponde al nombre de un paso. La idea es leer el currentStep y devolver el componente asociado. Para eso creas una función llamada getStepView.

Esta función recibe la configuración completa y el nombre del paso, y retorna el componente de React que debe pintarse en pantalla.

tsx const getStepView = <T, V extends string>( conf: StateMachineConfig<T, V>, stepName: V ): ComponentType<{ state: T; setState: Dispatch<SetStateAction<T>>; }> => { return conf.views[stepName]; };

Los genéricos T y V no son decorativos. T representa la forma del estado (nombre, edad), y V extiende de string porque siempre será el identificador textual de un paso. Así TypeScript te ayuda a no equivocarte al pasar pasos que no existen.

Una vez tienes la función, obtienes el componente y lo guardas en una variable para usarlo dentro del return:

tsx const StepComponent = getStepView(stateMachineConfig, currentStep);

Cómo controlar el avance entre pasos con handleNext

El botón Next solo debe aparecer cuando no estás en el paso final de confirmación. Si estás en step1 o step2, lo renderizas; si estás en confirmation, lo ocultas [07:30].

La lógica de avanzar vive en una función llamada handleNext. Antes de cambiar de paso, consulta a la configuración si el estado actual cumple las condiciones con el método canAdvance.

tsx const handleNext = () => { const canAdvance = stateMachineConfig .steps[currentStep] .canAdvance(wizardState);

if (canAdvance) { if (currentStep === 'step1') { setCurrentStep('step2'); } else if (currentStep === 'step2') { setCurrentStep('confirmation'); } } else { alert("You can't move forward yet"); } };

Fíjate en el detalle: la validación de si el nombre está completo o la edad es válida no vive en el componente, vive en la configuración de la máquina. El componente solo pregunta y reacciona.

¿Qué hace canAdvance exactamente? Es un método de cada paso de la máquina de estados que recibe el estado actual y devuelve true o false. Por ejemplo, en step1 revisa que state.name no esté vacío antes de permitir pasar al siguiente paso.

Cómo conectar el componente con las props del wizard

El componente que devuelve getStepView espera dos props: state y setState. Le pasas el wizardState y el setWizardState que creaste arriba, y cada vista del wizard podrá leer y modificar la información compartida.

tsx return (

<section> <h1>State Machine Wizard 🪄</h1> <StepComponent state={wizardState} setState={setWizardState} /> {currentStep !== 'confirmation' && ( <button onClick={handleNext}>Next</button> )} </section> );

Para que todo cobre vida, exportas el componente con export default StateMachineWizard y lo importas en main.tsx reemplazando el App por defecto.

Algunos elementos clave para terminar el montaje:

  • Renombrar el archivo y la referencia de App a StateMachineWizard.
  • Ajustar el index.css con los estilos del repositorio de la clase.
  • Probar el flujo en el navegador escribiendo un nombre, avanzando, ingresando edad y llegando a la pantalla de confirmación.

Cuando lo abres en el navegador y completas el flujo, ves cómo el mismo componente cambia de vista sin recargar la página y sin lógica condicional dispersa. Toda la inteligencia vive en la configuración de la máquina, y el componente solo orquesta.

¿Qué otro caso de uso se te ocurre para aplicar máquinas de estado? Cuéntalo en los comentarios.