statelyai / xstate

Actor-based state management & orchestration for complex app logic.
https://stately.ai/docs
MIT License
26.87k stars 1.23k forks source link

xstate monitor #29

Closed krasimir closed 5 years ago

krasimir commented 6 years ago

Hey @davidkpiano,

I'm interesting in instrumenting xstate and I need hooks to bind to. Like for example an API that will allow me to monitor what's going on with the machines. Imagine a tool that shows you in real time what's going on and draws a graph for example. An API like this.

davidkpiano commented 6 years ago

Hey, awesome! What kind of things are you wanting to "listen" for? Since xstate's transition is purely functional, there is nothing to listen to.

In version 2, you can add onEntry and onExit handlers to states. However, they are not executed - they are simply specified on the result State object for you, the developer, to consume and execute however you'd like:

  const lightMachine = Machine({
    key: 'light',
    initial: 'green',
    states: {
      green: {
        on: {
          TIMER: 'yellow',
          POWER_OUTAGE: 'red',
          NOTHING: 'green'
        },
        // Handlers can be strings or fns. Always prefer strings - they're serializable.
        onEntry: 'enter_green',
        onExit: 'exit_green'
      },
      yellow: {
        on: {
          TIMER: 'red',
          POWER_OUTAGE: 'red'
        },
        onEntry: 'enter_yellow',
        onExit: 'exit_yellow'
      },
      red: {
        on: {
          TIMER: 'green',
          POWER_OUTAGE: 'red',
          NOTHING: 'red'
        },
        onEntry: 'enter_red',
        onExit: 'exit_red',
        ...pedestrianStates
      }
    }
  });

Example state result:

const nextState = lightMachine.transition('green', 'TIMER').effects;
// {
//   entry: ['enter_yellow'],
//   exit: ['exit_green']
// }

const effectImplementation = {
  exit_green: () => console.log('exited green!'),
  enter_yellow: () => console.log('entered yellow!')
};

// execute the effects yourself
effects.exit.forEach(exitEffect => effectImplementation[exitEffect]());
effects.entry.forEach(entryEffect => effectImplementation[entryEffect]());
krasimir commented 6 years ago

Thanks. I think this will work. I'll post the result here once it's done 🚀

davidkpiano commented 6 years ago

Great. I haven't announced V2 yet, but, uh, it's out 🙊 I just have to document it.

For now, the best way to see the capabilities is to look at the unit tests.

mehdi-cit commented 6 years ago

Interesting thread! I was thinking of implement something similar on top of xState (If it turns out I needed such thing). Maybe you'd consider having such thing -see explanation below- within xState itself. Not sure it's a good idea, maybe it's better implemented outside of xState.. am I making any sense?? just thinking out loud. Anyway, here's my idea: I'd have liked to have a way to not only listen to the sate machine (onEnter, onExit ...) but also a way to control it from outside the component itself. For instance, having onBeforeEnter and onBeforeExit with the option to cancel the state transition (forcing the component not to leave its state and maybe forcing i to transition to yet another state). For instance Component C1 has States S1, S2 and S3. Let' say it was transitioning from S1 to S2. I use the onBeforeExit to listen to it from outside C1. In that listening-function I might decide to let it proceed, or else I might decide to cancel and stay in S1 or even to instead to transition to S3. In the above scenario, we'd also need the ability to alter C1's "data state" as well (not just its state machine but any part of its state). Don't read too much in the above text. Just some random ideas of how one can use xState. Again, it could very well be that it's much better to implement the above scenario outside xState!! Cheers~

krasimir commented 6 years ago

@mehdi-cit I kinda feel that such hooks need to be used only for debugging purposes. You shouldn't control the transitions or the state of the machine from the outside because this is breaking the deterministic nature of the tool. Or in other words the machine should be in full control of its state and transitions.

mehdi-cit commented 6 years ago

I hear you, but I still think it might be useful .. not sure... it just might! I will share my experience here if i ever get around doing such thing!

davidkpiano commented 6 years ago

Cool ideas @mehdi-cit, but I agree with what @krasimir said, and although those features would be "nice," you would suffer from increased complexity. The goal is to make the nested state machines (and statechart) as simple, declarative, deterministic, and statically analyzable as possible.

having onBeforeEnter and onBeforeExit with the option to cancel the state transition

The option to "cancel" a state transition is handled by "guard conditions" - the state transition isn't canceled per se; instead, in statechart semantics it is simply not chosen. The guard cond prop for transitions (see the tests) handle this nicely.

With that said, onBeforeEntry/Exit redundant with onEntry/Exit.

also a way to control it from outside the component itself

The machines are simply "configuration" and the state transitions are pure, so "controlling" an xstate state machine would have no effect. Its purpose is just to report to you, the developer, what the next state is going to be, so that you can update the state any way you'd like (and testing becomes much, much easier this way too).

Thanks for bringing it up though, I think these conversations are important!

krasimir commented 6 years ago

Hey @davidkpiano, can you point me to a really complex codepen that uses xstate? I need a full featured example to play with.

I have this and this.

davidkpiano commented 6 years ago

@krasimir I'm going to remake TodoMVC with React + xstate, would that suffice?

I have some super complex statecharts with xstate but they're in private code bases. (And yes they work great!)

krasimir commented 6 years ago

If the TodoMVC example uses statecharts I'll be fine with it. I just want to see how my tool behaves with a complex scenarios.

krasimir commented 6 years ago

Here's how one of the examples looks like in my extension:

image

It works but I wanna see some crazy events going on.

johncmunson commented 6 years ago

@davidkpiano Having a TodoMVC for React + xstate would be awesome. An example for React/Redux + xstate would also be awesome because I think "state" is referring to slightly different concepts when used in the context of statecharts as opposed to Redux (or some other state container), and I think this is confusing to a lot of people. I know it was for me.

davidkpiano commented 6 years ago

@johncmunson That's coming in the next version, where xstate will have full functionality as an external state container as well (still based on SCXML semantics, specifically <datamodel> and <assign>)!

johncmunson commented 6 years ago

That is very exciting!!! Love the work you're doing

davidkpiano commented 5 years ago

Redux dev-tools support added in master, will be released 🔜