XState

  • enumerate only the possible states to remove impossible states on your app video

Graph Theory

different type of nodes:

  1. Source nodes: nodes with no incoming edges
  2. Transfer nodes: nodes that have both incoming and outgoing edges
  3. Sync mode: nodes with no outgoing edges

Finite states

  • "you can be awake or sleep, but you CAN'T be sleep and awake at the same time"
  • Transitions are the edges
  • Events are the labels that needs to happen in order to transition from one state to another (from node to node)
  • There's only one initial state and ONLY one initial state
  • Final states: states where no more events can happen. is "Accepted"

Modeling state machines

  1. first add the states
  2. then we can start filling events

example of a simple machine:

1const machine = {
2 initial: "inactive",
3 states: {
4 inactive: {
5 on: {
6 CLICK: "active",
7 },
8 },
9 active: {
10 on: {
11 CLICK: "inactive",
12 },
13 },
14 },
15};

you can also write state transitions in two ways:

1const machine = {
2 initial: "inactive",
3 states: {
4 inactive: {
5 on: {
6 CLICK: "active", // shorthand of `target`
7 },
8 },
9 active: {
10 on: {
11 CLICK: {
12 target: "inactive",
13 },
14 },
15 },
16 },
17};

here's is how it looks a state machine

1// let's use a lightbulb example...
2
3// states are objects
4const lit = {};
5const unlit = {};
6const broken = {};
7
8// then we can combine our states in one object
9const states = { lit, unlit, broken };
10
11// we need an initial state
12const initial = "unlit";
13
14// then we can also combine states and initial state (config) and this is what we can pass to our state machine
15const config = {
16 id: "lightBulbMachine", // the config should have an ID
17 initial,
18 states,
19};

Now we need to enumerate all the possible events that our machine can handle. In order to do that, we need to define on every state the possible events that can be triggered to change the state, we do it with the on property on our state objects

1const lit = {
2 on: {
3 BREAK: "BROKEN",
4 TOGGLE: "unlit",
5 },
6};
7const unlit = {
8 on: {
9 BREAK: "BROKEN",
10 TOGGLE: "lit",
11 },
12};
13const broken = {};
14// because broken is the final state, we can leave the state object empty, but we can also add a `type: 'final'` on it to make it more explicit

by convention, the name of the event is capitalize, and the value of the event is the target state name we want to transition to.

Now we are ready to import the XState library to test it.

Actions

  • is a side-effect. this effects are considered the outputs of the state machine

Three types of actions:

  1. Transition actions: when transitions from one state to another
  2. Entry actions: when you enter a particular state
  3. Exit actions: when leaving a particular state

the order of the actions will be executed are:

  1. Exit actions
  2. Transition actions
  3. Entry actions
  • In general, don;t want to depend on action order too much. if you find yourself depending on the order too much, that's a sign that you need to model it different and maybe add an extra state

this is how actions looks like in XState:

1const machine = createMachine(
2 {
3 initial: "inactive",
4 states: {
5 inactive: {
6 entry: () => {}, // this could be an array of functions too
7 on: {
8 CLICK: {
9 target: "active",
10 actions: ["someAction", () => {}],
11 },
12 },
13 },
14 active: {
15 // ...
16 },
17 },
18 },
19 {
20 actions: {
21 someAction: () => {},
22 },
23 }
24);
  • the second parameter (the actions object) will override any actions inside the ones defined in the machine
  • finite states represents Qualitative data, it describes the behaviour

Extended state

  • describes Quantitative data. The combination of both (Finite + Extended state) describes your state machine
  • in XState is called context

Assignments

  • are actions
  • are pure fucntions. you need to get the prev state

Resources

1
© 2021, Powered by Gatsby