Hello XState Part 3: Writing my first state machines (and washing my hands)
Tags: xstate, statemachines, beginners
Published: 2020-07-21 20:26:15

<figcaption>Cover image by Wali's Studio for the <a href="https://unsplash.com/photos/TyxYX13uoMU" rel="external">UN COVID-19 Response</a></figcaption>

---

Previously in this series, we went through the default statechart / state machine example in XState Viz. 

{%link ekafyi/hello-xstate-part-2-exploring-the-xstate-viz-example-1nc1 %}

Now it’s time to write my own. I’m going to make a state machine for something we all do multiple times every day now: **washing our hands** 👏🏼💧. 

## Example 1: Just wash your hands

This is the most simple iteration of the “hand washing” story.

![visual diagram](https://dev-to-uploads.s3.amazonaws.com/i/3dxe3u9s38yy5kbipfw3.png)

{% gist https://gist.github.com/ekafyi/19d021954fa74235b3cf3c35c7e9b72c %}

- We begin with the initial state of `unwashed`.
- On the `START_WASH` event, we transition to the next state, `washing`.
- On the `STOP_WASH` event, we transition to the final state, `washed`.

💻 [Try it!](https://xstate.js.org/viz/?gist=https://gist.github.com/ekafyi/19d021954fa74235b3cf3c35c7e9b72c)

## Example 2: Delayed transition

Health experts recommend that we [scrub our hands for at least 20 seconds](https://www.cdc.gov/handwashing/when-how-handwashing.html). For the purpose of this example, I am simplifying the 20-second duration into the entire handwashing activity.

XState has a built-in feature for automatic delayed transitions—precisely what we are trying to do here—with the `after` property.

![visual diagram](https://dev-to-uploads.s3.amazonaws.com/i/b3cl7881dr9gzcyxpvpo.png)

{% gist https://gist.github.com/ekafyi/ea6e6f2fec6f482d4138e460deb65037 %}

- Initial state is `unwashed` (no change).
- On the `START_WASH` event, we transition to the next state, `washing` (no change).
- Now instead of the `STOP_WASH` event, we have a “timer” block that automatically takes us to the `washed` state after 20 seconds. We can see how a delayed transition is treated as a _special type of event_ here.

💻 [Try it!](https://xstate.js.org/viz/?gist=https://gist.github.com/ekafyi/ea6e6f2fec6f482d4138e460deb65037) (the timer animation is a nice touch!)

### Example 2b: Combining regular and delayed transitions

But what if I stop washing my hands before 20 seconds? Sure, we can allow that, but that _should not_ count as having washed our hands properly.  We can accommodate this by combining the regular transition (like in the first example) with the delayed transition.

![visual diagram](https://dev-to-uploads.s3.amazonaws.com/i/6miduvthml5nqnu8tv7y.png)

<figcaption>I mistyped the delay duration; it should be 20000ms instead of 2000 🤦🏽‍♀️</figcaption>

{% gist https://gist.github.com/ekafyi/47a68ddc98fd3472f0641cc6bcad3b9d %}

- We now have both the `STOP_WASH` event that we can run anytime, which transitions to the `unwashed` state.
- Once the timer reaches 20 seconds, we transition to the `washed` state.

💻 [Try it!](https://xstate.js.org/viz/?gist=https://gist.github.com/ekafyi/47a68ddc98fd3472f0641cc6bcad3b9d)

## Example 3: Hierarchical states

As we discuss the specifications of our hypothetical handwashing app with our hypothetical team, we learn that our application will involve a water tap, which will be either **on** or **off** at any given point.

Does the tap’s `on` state correspond to our current `washing` state, though? Maybe not. To preserve water, we may (should!) turn the water off while lathering and scrubbing, then turn it back on to rinse. All those are considered within the `washing` state. 

Let’s update our machine accordingly, this time taking advantage of XState’s hierarchical states. 

![visual diagram](https://dev-to-uploads.s3.amazonaws.com/i/p2qglpb9fqh2kewwfad3.png)

{% gist https://gist.github.com/ekafyi/f2a882ace48349be8cf8076e09082668 %}

- Everything other than `washing` is identical to example 2b.
- The `washing` state now has two **child states** (also known as **substates**): `tapOff` and `tapOn`. We achieve this by literally nesting a states object—in this case `tapStates`—inside the `states.washing` property.
	- `washing` is called a **composite state** because it has child states, while `unwashed` and `washed` are **simple states**.

💻 [Try it!](https://xstate.js.org/viz/?gist=https://gist.github.com/ekafyi/f2a882ace48349be8cf8076e09082668)

## Example 4: Parallel states

If we’ve got a tap, we must have a soap dispenser as well. Soap can only be dispensed while washing our hands, regardless of whether the water is running or not. This use case can be achieved with XState’s parallel states.

![visual diagram](https://dev-to-uploads.s3.amazonaws.com/i/zobycayeawaa914wmf5f.png)

{% gist https://gist.github.com/ekafyi/06ae8ab6a681d88518cb1f4687c7ddf1 %}

- `unwashed` and `washed` states are unchanged.
- `tapStates` are unchanged, except I renamed `TURN_ON` to `TAP_ON` (and its corresponding “off” state).
- In addition to `tapStates`, now we also have `soapStates` which defines the soap dispenser state. It can be turned on and off with the `SOAP_ON` and `SOAP_OFF` events.
- Then we have `washingSubstates` that contains two substates, `tapStates` and `soapStates`. We set `type: 'parallel'` to indicate that they are parallel (also known as *orthogonal*) nodes.
- Lastly, we add these substates as a substate of the `washing` state.

If we look at our code, we appear to have three levels of nested states now. But in reality—as the diagram suggests—we still only have two levels of nested states, with the second/middle substate serving as a “container” of the parallel states.

- `washing`
	- `washing.tapOff` or `washing.tapOn`
	- `washing.soapOff` or `washing.soapOn`

💻 [Try it!](https://xstate.js.org/viz/?gist=https://gist.github.com/ekafyi/06ae8ab6a681d88518cb1f4687c7ddf1)

## Conclusion

The examples above show simple use cases that demonstrates the basics of XState’s API, namely [transition delays](https://xstate.js.org/docs/guides/delays.html), [hierarchical (nested) states](https://xstate.js.org/docs/guides/hierarchical.html), and [parallel (orthogonal) states](https://xstate.js.org/docs/guides/parallel.html).. In a real-world implementation, we may need to create more complex statecharts with—among others—[conditionals](https://xstate.js.org/docs/guides/guards.html), [dynamic delays](https://xstate.js.org/docs/guides/delays.html#delay-expressions), and [context data](https://xstate.js.org/docs/guides/context.html).

Creating finite state machines “forces” us  to think about the way our application behaves—along with the requirements and implications—and document it before getting to the actual UI code (or the backend / API code for that matter). We trade efforts and dev hours upfront to avoid preventable bugs and wasted hours further down the road as the project and/or the team grows. 

From a frontend dev perspective, if your project is handed over to other developers, perhaps to be recreated or incorporated in a different stack, they would not have to comb over multiple `useState` hooks and nested JSX to find the states logic.

State machines and statecharts can be implemented with no external library or with other libraries, but I prefer XState as it provides handy functionalities for various use cases (like the examples here), which enables me to define my machine states in brief, simple, plain JavaScript objects. Finally, the visual interface of the XState Viz helps us develop, document, and communicate our state machines and statecharts.

Stay tuned for the next post, where I’m going to implement the state machines into the UI code. Take care and wash your hands!

---

## Bonus Track

By now we’ve done enough handwashing to be completely germ-free, so this song is fitting.

{% youtube MiWOuGC7Qy0 %}

---

## References

- https://xstate.js.org/docs/guides/delays.html
- https://xstate.js.org/docs/guides/hierarchical.html
- https://xstate.js.org/docs/guides/parallel.html