Left Arrow

Notes

State Management

A number of boxes connect by lines with arrows.

State Management

Last Tended

Status: mature

A bunch of stickers with 'Hello, my name is...' written on them

Named States

A common approach in React is to use boolean flags to keep track of state. For example, imagine we made a component that fetched an image. It could look like the following:

MyImageFetcher.tsx

const MyImageFetcher = () => {
    const [isFetching, setFetching] = useState(false);
    const [isSuccess, setSuccess] = useState(false);
    const [isError, setError] = useState(false);
    ...

A disadvantage of this is it results in untended states. The intended amount of states for the component is 4; idle, fetching, success & error. The actual number of states produced from the above approach is 23 = 8. Changing the approach from boolean flags to named states can fix this:

MyImageFetcher.tsx

type State = 'IDLE' | 'FETCHING' | 'SUCCESS' | 'ERROR'

const MyImageFetcher = () => {
    const [state, setState] = useState('IDLE');
    ...

Intended number of states = 4. Actual number of states = 4.

2 cogs

Finite-State Machines

When state management requirements become complex, finite-state machines are the best approach to UI state management.

React devs: if your app logic is super simple and only requires fetching + displaying data (CRUD), the only state management you really need is React Query + *maybe* useState. Consider state management libraries when the logic gets more exciting than that. The second your app needs shared state, multi-step user flows, stateful logic, advanced user interactions, etc., your app graduates from "simple" to "complex"
David K. Piano - founder of Stately

Advantages

  • Disable all user actions by default: Within each state, you have a centralized area where you define what events can occur, reducing edge cases.
  • Seperation of concerns: Logic can be seperated from everything else. This allows logic to be reused when changing frameworks (such as moving from Angular to React), easier seperation of work between team members & easier testing / debugging.
  • Named states: is core to the structure (see above why this is an advantage).
  • Scalability: Statecharts scale well as complexity grows. You can easily manage distributed behavior through the actor model.
  • Visualization: Logic can be visualized as a diagram (known as a statechart), acting as accurate documentation, making it easier to understand a system & acting as a communication language between coder / non-coder stakeholders.
  • Exploration: The process of building a statechart encourages all states to be explored. This can prevent edge cases from being overlooked.
  • Battle proven: 30+ years of refinement.
  • Formalised logic: increasing a codebase's consistency.

Disadvantages

  • Steep learning curve: State machines are a significantly different way of thinking about state when compared to popular state management libraries such as Redux.
  • Over-engineering: A state machine may seem like going overboard when a small amount of state management is required, such as a toggle that only requires a "on" & "off" state. This can be achieved with a small amount of code using React's "useState" hook. The counter-argument to this is, often what begins as simple state grows in complexity. State machines may be more work to begin with but less work at scale.

Currently, XState is the most popular JavaScript finite-state machine library.

Best Practice

Naming Conventions

  • Events: when naming events performed by the user, accuratley describe what happened, not the intention of the user action. Example, when a user clicks a sign in button on a form, instead of signIn, name the event signInButtonClicked.
  • Context: when naming an action that updates a machine's context, prefix the action with assign. Example, when an action changes context.email, name the action assignEmail.

Storing State

Storing state from a previous session & restoring it can improve the UX (User Experience). Different approaches to storing state:

localStorage

Although any state stored here will not be available on different devices, it can be useful for websites that don't require sign-in (& therefore can't send state to be stored in a database). Example, a Real Estate website that shows houses available to purchase. If it had a min / max price filter, the values set could be stored in localStorage & retrieved / applied each time the user returns to the website.

sessionStorage

Similar to local storage except anything stored here will be cleared when the page session ends. Survives page reloads & restores.

Query Params

Key / values stored in a URL. Useful when there is a requirement for a user to send a page address to another user in its current state.

Database

The most feature rich & expensive storage approach.

A space ship's docking bay with various equipment.

Resources

People to Follow
David KhourshidCreator of XState. Founder of Stately

Where to Next?

└── JavaScript
Arrow pointing down
YOU ARE HERE
└── State Management
└── XState
A sci-fi robot taxi driver with no lower body