2

I'm writing a state chart with the xstate library.

The statechart represents a medium complex UI.

I've several parallel states, but for this questions let's take into account only two:

SelectionStatus, which represents the select item(s), differentiating between substates SelectedNone, SelectedOne, SelectedMany.

Operation, which represents current operation in progress. It has a substate named Idle (among some others, of course).

There're some events which trigger actions that loop back to Idle substate, without going to another State. Let's think of them as immediate actions, for example a removeSelected action which just deletes the selected item(s) (and there's the point of the question).

I'm adding conditions to event removeSelected to perform different actions if the selection is limited to a single item (a node in a tree actually) or many (a branch of a tree).

The syntax of xstate to describe actions and conditions for an event would then be:

removeSelected: {
    Idle: {
         cond: isSelectedOneGuard,
         actions: ['removeOne']
    },
    Idle: {
         cond: isSelectedManyGuard,
         actions: ['removeMany']
    }
}

Problem is that I'm writing two Idle keys at same object nesting level, which isn't valid.

I've considered restructuring the statechart to have two branches of operations as substates of the selection ones but it seems a cure far worse than the problem.

I've also considered using intermediate dummy states like RemovingOne and RemovingMany which would simply trigger a transition back to Idle, but I'm not so satisfied with it.

I could solve this issue by removing the guard condition, do the test in the a generic removeOneOrMany action handler, but I would then loose the info about the different handling in the statechart.

Anybody had a similar problem and can provide some suggestion about this?

(Note: This is referring to current version of xstate, which is 3.1.1, 3.2 is almost there and I don't know if it could permit to handle this case more easily)

Thanks!

jonahe
  • 4,820
  • 1
  • 15
  • 19
AnimaLupi
  • 23
  • 5

1 Answers1

6

With the current syntax (3.1), you can put the different "candidate transitions" in an array:

removeSelected: [
  {
    target: 'Idle',
    cond: isSelectedOneGuard,
    actions: ['removeOne']
  },
  {
    target: 'Idle',
    cond: isSelectedManyGuard,
    actions: ['removeMany']
  }
]
David Khourshid
  • 4,918
  • 1
  • 11
  • 10