matthewp / robot

🤖 A functional, immutable Finite State Machine library

Home Page:https://thisrobot.life

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`onChange` not called for `immediate` states

ehuelsmann opened this issue · comments

In the state machine below, the callback is never called for the removing state, because send() never terminates its processing in that state.

However, the fact that the transition(s) out of the removing state is/are immediate() are an implementation detail that the callback user should not be aware of. Essentially, the state machine passes through this state and therefore, the callback should be notified.

const toastMachine = createMachine(
    {
        showing: invoke(
            delayRemoval,
            transition("done", "removing"),
            transition("error", "error", reduce(handleError))
        ),
        removing: state(immediate("removed")),
        removed: state(),
        error: state()
    },
    (ctx) => ({ ...ctx })
);

I think this is relatively simply resolved by calling onChange at the end of each enter() or transitionTo() instead of at the end of send().

This isn't a problem for invoke type transitions, because these use the service.send() function to transition to the next state and this function ends its processing by calling the callback.

I stand corrected: researching the call-flow more, I see that the enter call to the immediate state is what's taking it to the next state, which means that hooking this up on transitionTo() doesn't work. Doing it in enter() would, but at that point, the service hasn't been updated with the new machine yet, which means that the callback (which expects the latest machine to be in service.machine) can't get to the current state of the service.

Although not as trivial as calling "onChange" where originally indicated, the required change is still very limited, see PR #180.

Closed after reviewing the associated PR, decided to remain consistent with how XState does this.