React 19 de Cero a Experto / Estado global
Máquinas de estado y XState
Algunos estados no son datos sueltos, sino FLUJOS con reglas: de "cargando" solo se puede pasar a
"éxito" o "error", nunca volver a "inactivo" de la nada. Modelar eso con booleanos sueltos
(cargando, error, listo) lleva a combinaciones imposibles —¿qué significa cargando: true y
error: true a la vez?—. Las MÁQUINAS DE ESTADO lo resuelven: estados nombrados y transiciones
explícitas. Hoy construyes tu propia mini-máquina en vivo (la lavadora del SC-02, revisitada) y luego
ves XState, la librería que las lleva al máximo.
La lavadora que no se salta pasos
Tu mini-máquina, en vivo
Una máquina es una tabla que dice, para cada estado, qué eventos lo llevan a qué otro estado.
useReducer (módulo 2) la ejecuta de maravilla. Aquí una máquina de carga de datos corriendo:
Pulsa "Cargar": pasa a cargando, y ~1.2s después a exito o error. "Reintentar" solo funciona
desde error. La tabla transiciones es la máquina: cada estado declara a qué otros puede ir, y
maquina ignora los eventos inválidos (?? estado). Es IMPOSIBLE estar "cargando y con error" a la
vez, porque el estado es UN valor nombrado, no una bolsa de booleanos. Eso elimina toda una categoría
de bugs. Y fíjate: es useReducer (módulo 2) con una tabla —máquinas de estado y reducers son
parientes cercanos—.
XState: máquinas con esteroides
XState es la librería que lleva esta idea al extremo: define la máquina como un objeto declarativo, con estados, transiciones, acciones, guardas y hasta estados anidados. Compara la estructura con tu tabla —es la misma idea, más formal—:
import { createMachine } from "xstate";
import { useMachine } from "@xstate/react";
const maquinaDatos = createMachine({
id: "datos",
initial: "inactivo",
states: {
inactivo: { on: { CARGAR: "cargando" } },
cargando: { on: { OK: "exito", FALLO: "error" } },
exito: { on: { CARGAR: "cargando" } },
error: { on: { REINTENTAR: "cargando" } },
},
});
function Componente() {
const [estado, enviar] = useMachine(maquinaDatos);
return (
<div>
<p>Estado: {estado.value}</p>
<button onClick={() => enviar({ type: "CARGAR" })}>Cargar</button>
</div>
);
}createMachine con su states y on ES tu tabla de transiciones, en formato declarativo.
useMachine es tu useReducer. Encima, XState añade: ACCIONES (efectos secundarios en las
transiciones), GUARDAS (transiciones condicionales), estados ANIDADOS y PARALELOS, actores, y una
herramienta visual que DIBUJA tu máquina como un diagrama. Se instala con pnpm add xstate @xstate/react.
¿Qué problema resuelven las máquinas de estado y cuándo conviene XState frente a useReducer?
Mini-reto
Diseña una máquina para un semáforo: 1) estados verde, amarillo, rojo; 2) un solo evento
SIGUIENTE que cicle verde → amarillo → rojo → verde; 3) impleméntalo con una tabla de transiciones
y useReducer, con un botón que envíe SIGUIENTE y muestre el color. Bonus: agrega un estado
intermitente al que solo se llegue con un evento EMERGENCIA desde cualquier estado. Comprueba que
es imposible saltarse el orden.
Qué sigue
Ya tienes todas las herramientas de estado: local (useState/useReducer), compartido (Context),
global (Zustand), de servidor (TanStack Query), y de flujos (máquinas de estado). La próxima lección
las ORDENA en un mapa de decisión —cuál usar para qué, incluido cuándo Redux Toolkit— para que nunca
dudes qué sacar. Luego, el reto del módulo.