MicheleBertoli / react-automata

A state machine abstraction for React
MIT License
1.34k stars 60 forks source link

StateMachine Component #60

Closed ShMcK closed 6 years ago

ShMcK commented 6 years ago

I have a proposal, only half thought through, but I’d love to get some feedback.

StateMachine Component

Currently, in React Automata we wrap components with withStatechart to connect them to an instance of the state chart.

Statechart → wrapper → Component

As an experiment, I wonder if it might be easier if this extra level of abstraction could be removed.

Statechart → StateMachineComponent

While inheritance over composition is generally not a best practice, I think there is a case to make for creating an abstract React class for state machine management.

import { Machine } from 'xstate'

const StateMachine = Machine({ ... })

class SomeComponent extends StateMachineComponent<Props, States> {
  state = {}
  stateMachine = StateMachine
}

A StateMachineComponent might include:

Note that this would also resolve the issue of reusable state machines in #59.

ShMcK commented 6 years ago

An example of how using a StateComponent creates a significant simplification over withStatechart.

https://codesandbox.io/s/3yo97l1xrp

class StateMachineComponent extends React.Component {
  _currentState

  _handleActions = (actionList: string | string[]) => {
    if (actionList) {
      if (Array.isArray(actionList)) {
        for (const action of actionList) {
          if (this[action]) {
            this[action]()
          }
        }
      }
    }
  }

  transition(event) {
    const value = this._currentState
      ? this._currentState.value
      : this.stateMachine.initialStateValue
    const nextState = this.stateMachine.transition(value, event)
    this._currentState = nextState
    this._handleActions(nextState.actions)

    if (this.value !== nextState.value) {
      this.value = nextState.value
    }
  }
}
MicheleBertoli commented 6 years ago

Thank you very much for your proposal, and for building a concrete example @ShMcK. There are some scenarios where inheritance seems to simplify the code, but it should always be avoided as there are alternative approeaches that we can apply so I'm closing this for now.