javascript / intermediate
Snippet
Managing Multi-State UI Transitions with Discriminated State Machine Objects
Instead of juggling multiple disjointed boolean flags (like isLoading, isError, isSuccess), using a single discriminated state object with frozen enum-like string constants guarantees valid state transitions and simplifies conditional control flow via switch statements.
snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { useState } from 'react';const UI_STATUS = Object.freeze({IDLE: 'idle',SUBMITTING: 'submitting',SUCCESS: 'success',FAILURE: 'failure'});export function AsyncActionView() {const [state, setState] = useState({ status: UI_STATUS.IDLE, error: null });const executeAction = async () => {setState({ status: UI_STATUS.SUBMITTING, error: null });try {await new Promise((res) => setTimeout(res, 1000));setState({ status: UI_STATUS.SUCCESS, error: null });} catch (err) {setState({ status: UI_STATUS.FAILURE, error: err.message });}};switch (state.status) {case UI_STATUS.SUBMITTING:return <button disabled>Processing...</button>;case UI_STATUS.SUCCESS:return <p className="success-msg">Operation completed successfully!</p>;case UI_STATUS.FAILURE:return <div className="err-banner">Error: {state.error}</div>;case UI_STATUS.IDLE:default:return <button onClick={executeAction}>Start Action</button>;}}
react
Breakdown
1
const UI_STATUS = Object.freeze({
Creates an immutable dictionary of constant status identifiers to avoid typos and invalid states.
2
const [state, setState] = useState({ status: UI_STATUS.IDLE, error: null });
Consolidates related UI status and payload data into a single predictable state container.
3
switch (state.status) {
Evaluates the active discriminator to render the exact matching UI branch cleanly.
4
case UI_STATUS.SUBMITTING:
Handles intermediate async state by presenting a disabled loading indicator.