β€’

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