I’ve heard of state machines before; probably clicked a link or two; but never looked further. I had an impression of something super difficult and “computer-sciency”. I also could not imagine where and how it would fit in my day-to-day web development workflow.
Boy, I couldn’t have been more wrong.
This talk by Prabu Rangki cleared my misconception and got me hooked (heheh) on state machines, specifically XState. This is the first post in–hopefully 🤞🏽–a series that documents my journey to learn XState.
So… what are these things, exactly?
A State Machine (also known as Finite State Machine) is a pattern.
It’s a mathematical model of computation with implementations all across various science and programming fields. Wikipedia definition:
A [state machine] is an abstract machine that can be in exactly one of a finite number of states at any given time. The FSM can change from one state to another in response to some external inputs; the change from one state to another is called a transition. An FSM is defined by a list of its states, its initial state, and the conditions for each transition.
A basic example of the state machine model is the traffic light. It has 3 states※:
yellow. It can only be in one state at any given time, and it has specific conditions for transition between states (ie.
red can only go to
※ Except for one near my place, that sometimes go into an
off state at nights and would start working again during the day.
To learn more about state machines, check out the links at the end of this post.
There are other state machine libraries or, if you only need the most simple implementation, you can write your own.
XState, however, has additional functionalities for various use cases; and as a popular state machines library it has numerous tutorials and learning resources. For this reason I’m going to start with this library.
A large portion of modern web development, especially the frontend, is about dealing with states at various levels and rendering the appropriate UI.
For instance, in a page that shows a list of data (users, posts, products, etc), we render different views for at least three states:
While we’re still fetching data, we show
<div>Loading…</div><img src="spinner.gif" />.
Then as soon as we get the response,
- If the response is an error, we show
<div class="text-red-600">Oh no! There’s an error.</div>
- OR, we render the list of data if we get a successful response.
- If the response is an error, we show
In real-life apps, the scenario and user stories may be more complex and require more states.
Why do I want to use state machines for my application states?
Presentational UI components should deal with logic as little as possible. A button component only needs to know if it’s active or disabled. If active, I may style it with the brand color; otherwise I may gray it out and apply the
disabled attribute for accessibility.
Ideally, this is not the place to do things like:
- Check whether user has at least an item in the shopping cart (if a “Checkout” button)
- Check whether user has clicked once and now the app is sending/loading the data (if a “Submit” button)
We can abstract away the conditionals and functions for these tasks to the state machines, reducing potentially buggy nested conditionals and duplicated code in UI components.
Writing state machines help us focus on all the possible states, how the states relate to each other, and what actions can happen in each state, thus also ironing out all possible problematic/buggy scenarios, be it code issues or UX issues. It may force us to think at what level a particular machine should be in relation to a view or UI component.
You may notice that these benefits so far are not exclusive to state machines. Same things can be achieved with state management libraries like Redux; (if using React) APIs like HOC and Hooks; TypeScript to enforce data models and catch errors if you do something you’re not supposed to do in your current states. This next benefit is what sets XState apart from other solutions.
XState can be used in any modern JS app, with or without frontend framework. To me, versatility is a big selling point as it enables me to abstract my code away from any specific framework, thus avoiding being “locked” into it, and reuse it in multiple apps/products※※ regardless of stack.
※※ Untested hypothesis: I should be able to publish the machines code and have (eg.) a vanilla JS app an a React app import and use it, I believe?
In production apps, we work with stakeholders such as Project Manager, Product Owner, QA, and UI/UX Designer. Application states are often insufficiently documented, existing only in the codebase (API code, eg. Golang models, and frontend code, eg. Typescript definitions). We have to resort to temporary solutions like writing long descriptions in Jira and hopping on calls to ask for/clarify specifications verbally.
State machines can serve as the “single source of truth” for application states. They can be used as the basis for discussions, and once signed off on by all stakeholders, developers and designers can proceed with the implementation. Having this documentation can especially help frontend devs and UI designers on the same page regarding what design comps are needed.
That’s all for the intro post. Check out the next post to see more of the XState Visualizer!
XState is created by David Khourshid, who is a pianist and uses the handle @DavidKPiano online. It would be unacceptable if I did not use this opportunity to post this song called “Piano”! 🎹💃🏽
- XState Docs
- Welcome to the world of Statecharts by Erik Morgensen
- Guidelines for State Machines and XState by Kyle Shevlin
Talks by David Khourshid, XState creator:
- ReactiveConf 2018 – David Khourshid: Reactive State Machines and Statecharts
- David Khourshid: Simplifying Complex UIs with Finite Automata & Statecharts | JSConf Iceland 2018
- David Khourshid - Reactive State Machines and Statecharts - Uphill Conf 2019
Live coding videos: