There are 3 different things that can be executed when a state is entered:
actions and activities can furthermore be a sequence, containing multiple instances.
What is the execution order of all this? Is the above correct, and all of them finish before moving onto the next? (i.e. all the actions in onEnter will run before the first activity)
Activities are actions (specifically, special { type: 'xstate.start' } actions) and invoke is as well (e.g., { type: 'xstate.invoke' }).
⚠️ You should not depend on the order of these actions. You should consider them all called simultaneously. If actions depend on other actions, the machine should be modeled with additional states to specify that in a safe, deterministic way.
So as a sortof meta point, if any other action must run between an activity's start/stop, then the activity functions should rather be split into different actions which are run in different states - and if they need to persist data they should set it on the context.
Oth when I thought I needed this, I actually didn't ;)
What's the use-case for this? Maybe there's a better way to do it.
Yup, there's a _much_ better way! No more use case atm
All actions are completed before transitioning though right?
e.g. it's safe to have this, and clearContext will definitely update the context before loading state sees it?
{
onEntry: "clearContext"
on: { "": "loading" }
}
All actions are completed before transitioning though right?
No, not necessarily. Actions are side-effects.
Special actions, like assign and raise, are completed before transitioning.
Btw is that duo of onEntry plus transient state transition fairly common to address the issue raised here: to update context via an explicit state transition so that order is determinable?
Don't think of it that way (e.g., as a "duo"). Determine whether an action should be executed in one of three ways:
onEntry)onExit)actions)In this case:
// ❌ Do not do this!
{
onEntry: "clearContext"
on: { "": "loading" }
}
Your intention is (I assume) "When transitioning to "loading", the context should be cleared; i.e., the "clearContext" action should execute". That gives you a clearer idea of where that action should go:
// ✅ Much clearer
{
on: {
'': { target: 'loading', actions: 'clearContext' }
}
}
Another related question... when I listen to both state and context and re-render when either changes, from the perspective of the interpreter, the new state is reached before the new context is changed- despite actions being executed before that transition (as explained above)
Is this something that's controllable?
If unclear let me know and I'll do a codesandbox tomorrow (writi g this from my phone atm)
You typically don't need to listen to both state and context. Don't over-complicate it; just listen to state (.onTransition(...)), which includes context changes anyway.
But yes, you have full control of when actions are executed: https://xstate.js.org/docs/guides/interpretation.html#executing-actions
Ahh via state.context ?
My computer got killed by a power surge so I can't test this yet, but I think my problem above is just due to the order of .onChange and .onTransition which I can simply reverse? (I had onTransition first)
The order doesn't matter; the event listeners are async. Just use .onTransition(...).