The Statecharts community on Spectrum is (along with spectrum) MOVING TO OTHER PLATFORMS: For statecharts discussions in general go to Statecharts Discussion on GitHub (link) or Gitter (link). For XState-specific questions, go to the XState discussion forum for Q&A or the Stately discord chat to chat.
FAQ for Managing Hierarchy of XState Actors in ReactMarch 18, 2020 at 7:05pm (Edited 2 years ago)
xstate-react 0.8.0. Please respond if you have found better solutions.. these are just a summary of my findings I thought I'd share.
Should I spawn actors inside of XState or use the React model?
- You can use React Context for referencing parent state.
- If a child needs to send a message to a parent, put that logic in callback props passed to the child i.e.
- If a parent needs to send a message to a child, the child machine should subscribe itself to the parent and configure how it reacts to parent events.
- If parallel actors needs to communicate with one another, they should all subscribe to a common event bus to configure how they respond. Then, the components can send events to the bus which will to forward them along to other parallel actors. You might need some helpers so that parallel actors can subscribe to only certain events from the event bus (like those with a certain ID).
How do I simplify sending messages to actors? Should I send to an event bus, Observable, actor, etc?
How do I keep services decoupled but communicating? Where does all this wiring up happen?
What about deep message passing??
What about deep state access i.e. user state deep in a screen??
- Use React Context. Expose the top level actor/service through Context. Your child actors will need to be spawned by React instead of inside of XState, but that might be worth it until XState’s actor model matures. Since most state like this just needs to be used for display/rendering (not inside other machines), React will handle updates to it automatically. If you do need to update the state inside of a service, just use React hooks to send an UPDATE event when it changes.
- Use Observable streams. Instead of manually wiring up specific request/respond events, you can pass a stream around to always get the latest value. Instead of an event bus moderating, you’d use a stream. The parent component would hook up its context to the stream, and then the deep child component would import the stream through React context or a global registry like Redux/singleton.
- Use an event bus for requesting latest state. There would be some boilerplate, but you could hook up to an event bus that uses events to request a state from the publisher, and the publisher would send a response to all subscribers. Remember, the child would not know the state by default until it requested it. Since XState is not smart enough yet to communicate between services/actors started outside of XState, we can use an event bus and manually hook up the events. This is unfortunate boilerplate if the data is just used for rendering, but some helper code could simplify. NOTE: this could be an Observable to simplify.. see above.
- Use XState. Pass the state down through the actors. When the state is updated (like a User Setting change, you would manually propagate the USER_CHANGE event down through your child actors). However, this introduces the highest coupling, and it’s a poor representation of a much shallower relationship between the top-state and the child that needs it. Think about passing down an Observable hooked up to the parent's context if you’re limited to only managing machine through XState.
March 18, 2020 at 10:50pm
- Use the actor-model library (which I'm currently working on) as a very thin abstraction for organizing code/logic via the actor model
- Refine actor behaviors with XState
React IS the actor system spawning machines. Rather than XState.
March 24, 2020 at 11:45pm
March 25, 2020 at 1:25pm
March 27, 2020 at 10:34pm
May 7, 2020 at 11:00am
The consensus seems to be that XState loses its framework-agnostic status once you start having to manage multiple actors then?
July 7, 2020 at 5:24am
July 7, 2020 at 7:52pm
July 8, 2020 at 3:03am
July 8, 2020 at 1:36pm
you can "spawn" an actor by rendering a new component with it's own machine Exactly. The component is the actor here. We're just choosing not to use the XState specific API for spawning actors directly by a parent machine but rather letting ReactJS be the actor system here
July 9, 2020 at 2:58am
- A promise is an actor that doesn't receive any events and only ever sends back one event (at most).
- An observable is an actor that also doesn't receive any events and sends back 0 - infinite events.
- A service (interpreted machine) can send and receive any number of events.