If a transition is in array form like on: { DEACTIVATE: [ '.mode.inactive', '.status.disabled' ] } the transition does not work as expected. Not until the transition is in object form like on: { DEACTIVATE: { target: [ '.mode.inactive', '.status.disabled' ] } } does the correct behaviour occur when sending the event.
When sending an event that has multiple targets, the event should cause the transition regardless of how the transition is defined in the statechart (i.e. in array form or object form)
When sending an event that has multiple targets, no transition occurs IFF in the startchart the transition is in array form like: on: { DEACTIVATE: [...] }
I would assume the easiest fix would be to transform transitions defined as arrays into objects. So at the lower-level you only ever deal with transitions in a normalized, object form. In short, normalize the representation of transitions from a statechart.
Can be copy and pasted in the visualizer. Replace the DEACTIVATE: ['.mode.inactive', '.status.disabled'] with the commented out example then you will see the event buttons enable and the logs start to log as expected.
// Available variables:
// - Machine
// - interpret
// - assign
// - send
// - sendParent
// - spawn
// - raise
// - actions
// - XState (all XState exports)
const settingsMachine = Machine({
id: 'settings',
type: 'parallel',
states: {
mode: {
initial: 'active',
states: {
inactive: {},
pending: {},
active: {}
}
},
status: {
initial: 'enabled',
states: {
disabled: {},
enabled: {}
}
}
},
on: {
// Multiple targets
DEACTIVATE: ['.mode.inactive', '.status.disabled']
// Can also be coded as...
// DEACTIVATE: {
// target: ['.mode.inactive', '.status.disabled']
// }
}
});
const i = interpret(settingsMachine)
i.start()
i.onTransition((s, e) => {
console.log('here', e)
console.log(s.value)
})
i.send('DEACTIVATE')
I'll look into fixing this today/tomorrow.
Actually... I think this works correctly.
{
DEACTIVATE: ['.mode.inactive', '.status.disabled']
}
is an equivalent of
{
DEACTIVATE: [{
target: '.mode.inactive',
}, {
target: '.status.disabled'
}]
}
This is a "conditional" transition, only with implicit () => true guard.
In general, specifying such transition doesn't make sense, because always only the first one will get picked up. We could do a better job here and provide a nice dev-only warning though, to make the error on your side more obvious.
@davidkpiano have you added an enhancement label for the warning I was talking about or had you smth different in mind?
For the warning. The dev-only heuristic should be if the first target (in an array of > 1 targets) doesn't have a condition, then it was probably configured wrongly.
This perhaps works in a different version of XState than the visualizer uses. Our application could benefit from multiple targets and wanted to test the example in the guide here ( https://xstate.js.org/docs/guides/transitions.html#multiple-targets ) in the visualizer before we committed to using multiple targets, but the visualizer appeared to not work correctly when the transition was defined as an array like in the guide.
Hmm, just re-read the discussion here. Wouldn't this imply the part of the guide that describes multiple transition targets is incorrect then?
See: https://xstate.js.org/docs/guides/transitions.html#multiple-targets
Sorry about this, I'll fix it in the docs! We'll also add a dev-time warning if the usage is incorrect.
Most helpful comment
I'll look into fixing this today/tomorrow.