Frontend Quick Tips #16 How to Escape From Boolean Trap With State Machines

Photo of Bernard Klatka

Bernard Klatka

Updated Jan 9, 2023 • 3 min read
Paying for the service

No one likes those big articles - that’s why we’re creating Quick Tips - short tips to change your developer's life from the moment you read them.

Those may be some patterns explained in JS code on real-life examples or some techniques for better code.

Problem

In a typical scenario when an application needs to connect to external resources/services (e.g. by API) to gather some data, our component’s state (or state container) has a bunch of boolean flags with a lot of conditional checking, where the initial state is:

{

isPending: true,

isFulfilled: false,

isRejected: false

}

and the next state (e.g. when request is successfully fulfilled):

{

isPending: false,

isFulfilled: true,

isRejected: false

}

Solution

Use a state machine

Quoting Wikipedia, a state machine (or FSM) is:

"It 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 inputs; the change from one state to another is called a transition".

I have prepared a super simple and minimal state machine, you can get it here:

https://gist.github.com/serrg/e794b30b8dc3ebee29b096770f075b1c

Now your component’s state (or state container) could be like:

{

state: {}

}

Where state is your state machine with declared transitions and status:

const machine: Machine = createMachine<State>({

init: "idle",

transitions: [

{ name: "start", from: "idle", to: "pending" },

{ name: "success", from: "pending", to: "fulfilled" },

{ name: "failure", from: "pending", to: "rejected" }

],

actions: {

start: () => {

console.log("action started");

},

success: () => {

console.log("action successed");

},

failure: () => {

console.log("action failed");

}

}

});




machine.state; // state: idle

machine.action("start"); // action started, state: pending

machine.action("success"); // action successed, state: fulfilled

machine.action("failure"); // action failed, state: rejected

By using a machine.state property rather than a boolean flag indicator we enable our users to know exactly what the state is at any given point in time.

Our flow now looks like:

diagram

There are more complex and more powerful state machines, you can find libraries for any framework or language here: https://github.com/leonardomso/awesome-fsm. When it comes to frontend, the most popular library is XState.

Photo of Bernard Klatka

More posts by this author

Bernard Klatka

Read more on our Blog

Check out the knowledge base collected and distilled by experienced professionals.

We're Netguru

At Netguru we specialize in designing, building, shipping and scaling beautiful, usable products with blazing-fast efficiency.

Let's talk business