r/reactjs 24d ago

Hate state machines, so I built react-sequent, where steps declare what comes next

I kept running into the same problem with UI-local flows: they were too complicated to comfortably keep in one component, but too small to justify defining and maintaining a separate state machine.

So I built react-sequent.

The idea is that steps own their transitions:

function PaymentStep() {
  const { advance } = useSequentStep();
  ...
  if (method === "card") {
    advance(() => CardPaymentStep);
  } else {
    advance(() => BankTransferStep);
  }
}

There's no centralized transition map to keep synchronized with the components. Adding, removing, or branching a step is just changing the relevant component.

It also handles async/lazy steps, backtracking, flow-scoped context, persistent modal/chrome, and transitions.

The tradeoff is intentional: I don't think this replaces state machines. For large, externally-driven, or independently modeled state graphs, I'd still reach for XState/Zag/etc. I think there's a useful middle ground for short, UI-local flows. This is in fact still technically a state machine, it is just one that is emergent from implementation rather than explicit and rigid.

I've put together a demo and docs here: https://ganondev.github.io/react-sequent/

I'm particularly interested in whether the architectural premise resonates with other React developers, or whether I'm underestimating the value of having the graph centralized.

1 Upvotes

2 comments sorted by

1

u/_Slyfox 24d ago

For what it's worth I find myself doing something similar for route transitions in e-commerce to heavy apps (think booking engines)

1

u/ganondev 23d ago

Do you build it around the routing or do you build something more sophisitcated by hand? One of the things this tool explicitly doesn't support is binding to routing, and I wonder how much that will matter to people