State machine advent: From implicit to explicit state machine (6/24)
Tags: javascript, typescript, react
Published: 2019-12-06 12:40:15

In my research about state machines, I heard @davidkpiano talk about the fact that all of us are already using state machines. Most of them are just implicit. In today's post, I'll cover implicit state machines and showcase why you should reach for an explicit state machine instead.

Implicit state machines do not enforce the `state + event => newState` formula that should drive our UI. They oftentimes change state within event handlers and are usually plagued by a lot of conditional logic. The simplest version of such an implicit state machine written purely in React can be seen below or in this [codesandbox](https://codesandbox.io/s/stupefied-architecture-4x8mx).

```jsx
import React, { useState } from "react";
import Switch from "react-switch";

const LightSwitch = () => {
  const [active, setActive] = useState(false);

  return (
    <Switch
      onChange={() => setActive(!active)}
      checked={active}
      aria-label='Toggle me'
    />
  );
}
```

This is one of the simplest stateful React components and it's working great. What could possibly be wrong with the implementation above? 

It starts with `useState`. We pass an initial state and then perform a state update using `setState` in event handlers. Whenever this occurs, we have created a component whose behavior can't easily be reused. The initial state of our component is tightly coupled and encapsulated to our React component. If we want to reuse our logic (including the initial state), we might want to reach for a custom hook instead.

```javascript
const useSwitch = () => {
  const [active, setActive] = useState(false);

  return [active, setActive]; 
}
```

This custom hook allows us to share the initial state of `false` for any component that'd like to implement a stateful switch component. However, each component implementing this hook will have to directly call `setActive(!active)` as soon as someone clicks on the switch. We can fix this by making a minor change to our custom hook.


```jsx
const useSwitch = () => {
  const [active, setActive] = useState(false);

  const toggle = () => void setActive(!active); 
  return [active, toggle]; 
}

const LightSwitch = () => {
  const [active, toggle] = useSwitch();

  return (
    <Switch
      onChange={toggle}
      checked={active}
      aria-label='Toggle me'
    />
  )
}
```

Instead of exposing the `setActive` hook directly, we expose a function that acts as an event that ultimately drives our state changes.  
Sweet. We've abstracted our implicit state machine into a custom hook that encapsulates the exact behavior as our explicitly defined state machine from [yesterday](https://dev.to/codingdive/state-machine-advent-invoking-a-state-machine-in-react-1nm7).
This worked pretty well but it's worrisome just how easy it is to forget that events should drive state changes. Needless to say, as your application logic and state architecture grows beyond two possible boolean values and one event, you'll undoubtedly introduce a lot of bugs by using implicit machines and miss out on all the benefits of explicit state machines such as [visualization](https://dev.to/codingdive/state-machine-advent-visualize-your-state-machines-with-diagrams-as-you-code-4-24-1m7b). 

In summary:

* It's very easy to forget `state + event => newState` because React encourages to perform state updates in event handlers. Send events in event handlers and your code will improve. The only way to enforce this is by strictly modeling your application with state machines.
* If you want to fully separate behavior from your component, reach for explicit state machines immediately.
* `useState(boolean)` especially if you have two or more interdependent local states is a huge red flag and indicates that you should probably go with an explicit defined state machine.


[Codesandbox explicit state machine in xstate](https://codesandbox.io/s/awesome-dewdney-7isp2)

[Codesandbox implicit state machine](https://codesandbox.io/s/stupefied-architecture-4x8mx)

[Codesandbox a better event-driven implicit state machine using custom hooks](https://codesandbox.io/s/green-pond-h9vmr)


### About this series
Throughout the first 24 days of December, I'll publish a small blog post each day teaching you about the ins and outs of state machines and statecharts.

The first couple of days will be spent on the fundamentals before we'll progress to more advanced concepts.