>Both of these libraries' React integration involves creating a "service" that accepts events and transitions between states internally, bypassing React's own state management lifecycle, which is tightly integrated with rendering. In the past I've seen a number of nasty bugs pop up when precise synchronization between theses two sources of truth for state is required, and they can be a bit of a nightmare to debug and/or work around.
I've been using XState and React on a fairly sophisticated large scale application for the last two years. The key is using React hooks with pure components, and eschewing the lifecycle altogether. This turns React basically into just a highly efficient view rendering library, while delegating all of your application logic to the state machine. Your components end up way cleaner and easier to reason about when they are just pure functions without side effects, and all your business logic is contained within a state machine.
I think that's certainly a valid approach, and comes with a ton of benefits. But I don't think that has to be the _only_ viable approach to use a state machine in React without having to worry about subtle synchronization bugs.
Especially since even if our endgame is to go all-in on the state machine as our only source of truth for state, we could still benefit from a smooth transition path to get there.
Using state machines deliberately for complex flows while delegating simpler state management tasks to simple useState hooks should ideally be just as robust and well supported as modeling our entire UI as a giant state machine.
At the end of the day, the state machine definition in both of these libraries is just a bunch of data, to be interpreted by some runtime that's responsible for maintaining internal state and reacting to events. Currently that runtime is a generic stateful "service" implementation provided by these libraries, but there's no reason why that runtime couldn't be some stateful service implementation built on top of React, or any other view layer with its own opinions on state management.
”Currently that runtime is a generic stateful "service" implementation provided by these libraries”
This is how I approached using XState in a proof of concept last year. I created a “service layer” made up of XState machines that handled different high-level aspects of the application behaviour; i.e. not tied specifically to a particular UI element. Things like managing the requests made during an OAuth flow and storing the authenticated user’s information.
This gave me a source of application state with well defined behaviours that I could use instead of “redux” and its usual accompaniment of boolean flags and thunks.
The best part of embracing the separation of state management from React is that I initially developed the application in Angular before lifting-and-shifting the “service layer” over to React and sticking in a “context”. All the application behaviours remained the same, it was just a matter wiring up some JSX in place of Angular’s HTML templates.
> The key is using React hooks with pure components, and eschewing the lifecycle altogether.
Can someone explain this in a little more detail? Particularly the eschewing the lifecycle altogether. Does this basically mean delaying the view render until all the business logic is evaluated, aiming for only one render per operation?
>Can someone explain this in a little more detail? Particularly the eschewing the lifecycle altogether.
We use it in conjunction with MobX observers, so that a component is only ever rerendered when its' data is updated, and there's no fooling around with `componentDidUpdate` stuff that can get unwieldy really fast.
The interaction flow is basically: Click handler -> Send event to the state machine -> State machine evaluates business logic, calls services, etc. and updates MobX model -> MobX observer rerenders the pure functional React component. So that all your components are ever doing is sending events to the state machine, with no business logic baked in. Use `useState` for ephemeral component level state like toggle switches, but the source of truth for the entire application lies in MobX models updated by state machines.
I've been using XState and React on a fairly sophisticated large scale application for the last two years. The key is using React hooks with pure components, and eschewing the lifecycle altogether. This turns React basically into just a highly efficient view rendering library, while delegating all of your application logic to the state machine. Your components end up way cleaner and easier to reason about when they are just pure functions without side effects, and all your business logic is contained within a state machine.