Bug (or a question)
When using nested / hierarchical state machines, transitions to nested states cause onEntry/onExit actions / restarting activities
const XState = require("xstate")
const { Machine, interpret } = XState
const testMachine = Machine(
{
id: "test",
initial: "foo",
states: {
foo: {
initial: "bar",
on: {
RESET: `#test.foo.bar`,
},
onEntry: `enter`,
onExit: `exit`,
activities: `fooActivity`,
states: {
bar: {
on: {
TOGGLE: `baz`,
},
},
baz: {
on: {
TOGGLE: `bar`,
},
},
},
},
},
},
{
actions: {
enter: () => {
console.log("enter 'foo'")
},
exit: () => {
console.log("exit 'foo'")
},
},
activities: {
fooActivity: () => {
console.log("start activity in 'foo'")
return () => {
console.log("stop activity in 'foo'")
}
},
},
}
)
const service = interpret(testMachine)
.onEvent(ev => {
console.log(`EVENT ${ev.type}`)
})
.onTransition(state => {
console.log(`STATE ${JSON.stringify(state.value)}`)
})
.start()
service.send("RESET")
Should not fire onExit and onEnter actions / restart fooActivity activity on sending RESET action as foo state is still active
start activity in 'foo'
enter 'foo'
EVENT xstate.init
STATE {"foo":"bar"}
exit 'foo'
stop activity in 'foo'
start activity in 'foo'
enter 'foo'
EVENT RESET
STATE {"foo":"bar"}
foo is never left, but onExit etc is called
I didn't dig into the code yet. First, I'd like to ask for clarification if current behaviour is expected or it should be considered as bug. Hierarchical State Machines docs doesn't cover enter/exit actions / activities behaviour.
https://runkit.com/pieh/5c7c95a947703a00120db854 (same code as above) or copy & paste Machine to XState Visualizer, click "reset" event and check browser console
~Looks like a bug to me.~ Does it change things if you change RESET: '#test.foo.bar' with RESET: 'bar'?
Edit DOH! Sorry, It must be early. No, this isn't a bug. the transition from a compound state to its children should exit the compound state, and then reenter itself.
To avoid that, try declaring the transition as being an internal transition. This will let the compound state remain active. The difference is also explained on statecharts.github.io.
To avoid that, try declaring the transition as being an internal transition. This will let the compound state remain active. The difference is also explained on statecharts.github.io.
Thanks! This seems to work as I on quick test.
_No, this isn't a bug_. the transition from a compound state to its children _should_ exit the compound state, and then reenter itself.
Maybe adding some context to https://xstate.js.org/docs/guides/internal.html on why using full path vs internal path (to the same state) results in different side effect would be helpful? As issue suggests, I didn't expect that.
Another docs suggestion from me would be adding link to "internal transitions" on "hierarchical state machines" pages (This one I can PR this week :) )
Most helpful comment
~Looks like a bug to me.~ Does it change things if you change
RESET: '#test.foo.bar'withRESET: 'bar'?Edit DOH! Sorry, It must be early. No, this isn't a bug. the transition from a compound state to its children should exit the compound state, and then reenter itself.
To avoid that, try declaring the transition as being an internal transition. This will let the compound state remain active. The difference is also explained on statecharts.github.io.