โ€ข

tech

Underused XState patterns and benefits

From State of React it looks like only 10% of people used XState. I was one of those many moons ago, and after I discovered it, I never looked back. And the reasons are practical, let me tell you.


Sandro Maglione

Sandro Maglione

Software

The newest "State of React" results are out ๐Ÿš€

And XState is yet again underused and underappreciated (10% usage) ๐Ÿค”

It's time for a periodic update on what makes XState special (and needed) ๐Ÿ‘‡


AI rolls with it

First, no coding discussion is complete (anymore) without first mentioning AI ๐Ÿ’๐Ÿผโ€โ™‚๏ธ

AI works great with XState (in my experience and my codebases) ๐Ÿš€

No MCP or similar:

  • Clone xstate repo in local .agents directory, and point to it in AGENTS.md
  • Provide a few examples

Done. No need to worry about "complexity". The AI seems to thrive when code is structured, and nothing is more structured than states and state machines ๐Ÿ—๏ธ

Caveat: actors composition

The AI (and most people) has still problems in "properly" composing actors.

Left on its own, the AI starts creating multiple machines and opt for useEffect to react between each others events ๐Ÿ˜ฌ

Composing actors requires some nudging:

  • Added specific hint in AGENTS.md
  • Specifically ask for using actors
AGENTS.md
## State management
ALWAYS use `xstate` and `@xstate/react` IN ALL CASES for state management inside React components.
Implement all the logic inside a single `machine` that uses `setup().createMachine()`.
Leverage actors for composition.
A React component must have **a single** `const [snapshot, send] = useMachine(machine);` when correctly implemented.

You can inspect the official `xstate` repo inside
[.agents/xstate](./.agents/xstate/) to learn how to use all the `xstate` APIs.

Then, check the code (especially at the beginning, when patterns are less established), useEffect may sneak in unnoticed otherwise ๐Ÿ‘€

Beyond React state

This goes extremely underappreciated ๐Ÿ™Œ

XState, actors, state machines all go beyond "React state management" ๐Ÿช„

While they are an ideal fit for React, XState can be used in many other domains. Learn it once, play it everywhere โœจ

A recent example of mine: Web Workers.

A web worker is a "machine" that holds some state, and sends and receives events. Sounds familiar ๐Ÿค”

You guessed right, state machine!

const machine = setup(/* ... */).createMachine(/* ... */);

const actor = createActor(machine).start();

self.addEventListener("message", (event) => {
  const typedEvent = Schema.decodeUnknownSync(WorkerEvent)(event.data);
  actor.send(typedEvent);
});

You define the machine inside the worker, start it, and pipe the events into it. From the machine, you can send back events as well ๐Ÿช„

Syncing events

Another major pattern is event syncing ๐Ÿ“ง

Many APIs provide some sort of "subscription" API. Good luck syncing multiple subscriptions manually ๐Ÿซ 

A good example is BroadcastChannel for tabs syncing.

With XState, instead of "manual" useEffect and chaos, you create a single "piping" actor: takes events and sends it back to the main machine, nothing else ๐Ÿซก

const broadcastActor = fromCallback(({ sendBack, receive }) => {
  const channel = new BroadcastChannel(CHANNEL_NAME);

  receive((event) => {
    const typedEvent = Schema.decodeUnknownSync(BroadcastEvent)(event);
    channel.postMessage(typedEvent);
  });

  channel.addEventListener("message", (event) => {
    const typedEvent = Schema.decodeUnknownSync(BroadcastEvent)(event.data);
    sendBack(typedEvent);
  });

  return () => {
    channel.close();
  };
});

This same pattern can be used everywhere the same (listening for audio/video events, gestures, tabs).

All the complexity is reduced in the main machine as simple events ๐Ÿ“ง

v6?

Still unsure? Just wait for the upcoming XState v6 ๐Ÿ‘€

v6 is currently work in progress behind the scenes.

The promise of v6 is strong: simple and more powerful. And, even more important (for me): more type safe ๐Ÿงฑ


xstate solves state management (soon with even more precision and type safety), and effect, well, everything else.

In fact, those are the only two "business logic" dependencies I have in my client apps (everything else is styling or specific SDKs).

See you next ๐Ÿ‘‹

Start here.

Every week I dive headfirst into a topic, uncovering every hidden nook and shadow, to deliver you the most interesting insights

Not convinced? Well, let me tell you more about it