Conectar XState con componentes React

Resumen

Conectar una máquina de estados con la interfaz es donde la teoría de XState se vuelve tangible. Aquí aprenderás a implementar eventos y transiciones dentro de un proyecto React, moviéndote entre pantallas según el estado actual de la máquina y mostrando u ocultando elementos según corresponda.

Esto te sirve si ya entiendes los conceptos básicos de máquinas de estado finitas y quieres conectarlas a componentes reales de una aplicación de booking.

Cómo se estructura el proyecto antes de conectar las transiciones

Antes de tocar la lógica, conviene entender qué piezas ya existen y cuáles vas a conectar.

En el repositorio de la clase encontrarás una carpeta public con imágenes de fondo, una carpeta containers donde vive el BaseLayout, y dentro de ese layout se renderizan dos componentes principales: el Nav superior y el StepsLayout debajo [00:48]. El StepsLayout actúa como el contenedor que decide qué pantalla mostrar: Welcome, Search, Passengers o Tickets.

¿Qué hace el StepsLayout en una máquina de estados? Es el componente que evalúa el estado actual y renderiza la pantalla correspondiente. Funciona como un switch visual conectado a la máquina.

Puedes clonar el branch de la clase ocho desde recursos para arrancar desde el mismo punto.

Cómo pasar la función send entre componentes en React

La función send es la encargada de disparar transiciones, y necesita viajar desde donde se inicializa la máquina hasta los botones que ejecutan eventos.

Desde el BaseLayout, donde ya tienes acceso a state y send gracias al hook de XState, los pasas como props al StepsLayout [02:30]. Ese componente, a su vez, los reenvía al Welcome, al Search, al Passengers y al Tickets. Así, cada pantalla puede disparar su propio evento sin saber nada del resto.

En el componente Welcome, el botón de comenzar tenía un console.log dentro de la función startBooking. Lo reemplazas por:

js send('START')

Al hacer clic, la máquina pasa de initial a search. Lo confirmas imprimiendo state.value en consola [03:50].

Cómo renderizar pantallas según el estado con state.matches

El método state.matches es la herramienta que conecta el valor de la máquina con lo que el usuario ve.

Dentro del StepsLayout, evalúas el estado y devuelves el componente correspondiente:

js if (state.matches('initial')) return <Welcome send={send} /> if (state.matches('search')) return <Search send={send} /> if (state.matches('tickets')) return <Tickets send={send} /> if (state.matches('passengers')) return <Passengers send={send} /> return null

Un detalle fácil de pasar por alto: si olvidas pasar state como prop al StepsLayout, obtendrás el error cannot read property matches of undefined [05:20]. Revisa siempre que tanto state como send estén llegando al componente que los usa.

¿Qué es state.matches en XState? Es un método que devuelve true si la máquina está en el estado que le pasas como argumento. Sirve para renderizado condicional sin escribir comparaciones manuales.

Cómo mostrar elementos solo en ciertos estados de la máquina

Una de las ventajas de tener una máquina de estados es que la UI se vuelve declarativa: muestras cosas según donde estés.

En el componente Nav quieres que el botón de cancelar aparezca solo cuando el flujo ya inició. La condición es simple:

js {!state.matches('initial') && <button onClick={gotoWelcome}>Cancelar</button>}

La función gotoWelcome ejecuta send('CANCEL'), que es el evento definido en el BookingMachine para todos los pasos [07:15]. Al darle clic, sin importar en qué pantalla estés, regresas al Welcome.

Este patrón te permite ocultar botones, mostrar avisos o cambiar vistas completas dependiendo del estado, sin acumular condicionales dispersos por toda la aplicación.

Cómo conectar el flujo completo de Search a Tickets

Con la base lista, solo falta cablear cada botón de continuar al evento correcto.

En Search, el botón de continuar dispara send('CONTINUE'), que mueve la máquina de search a passengers. El botón ya viene con la validación de estar disabled hasta que selecciones un destino, así que la transición no ocurre por accidente [09:00].

En Passengers hay un formulario con varios botones, pero por ahora solo conectas el de Ver mi ticket, que ejecuta send('DONE') para llegar al estado de tickets. La lógica de agregar pasajeros queda para una clase posterior.

En Tickets, el botón de finalizar ya tenía un console.log. Lo reemplazas por send('FINISH') y la máquina vuelve al initial, cerrando el ciclo [10:30].

¿Cómo se nombran los eventos en XState? Por convención se escriben en mayúsculas como strings: START, CONTINUE, CANCEL, DONE, FINISH. Deben coincidir exactamente con los definidos en la configuración de la máquina.

Con esto tienes el flujo base funcionando: Welcome a Search, Search a Passengers, Passengers a Tickets, y de cualquier punto puedes cancelar para volver al inicio.

¿Qué evento te gustaría agregar primero a tu propia máquina de estados? Cuéntame en los comentarios cómo lo estás aplicando en tu proyecto.