Home / books / learning-larc / diagrams / 06-state-management

State Management Patterns

State Hierarchy

graph TB
    subgraph "State Layers"
        subgraph "Component Local"
            CL1[Component 1<br/>_count, _visible]
            CL2[Component 2<br/>_expanded, _selected]
        end

        subgraph "Shared State"
            SS[Application State<br/>user, theme, cart]
        end

        subgraph "Persistent State"
            LS[localStorage<br/>Preferences, tokens]
            IDB[IndexedDB<br/>Large datasets, cache]
        end

        subgraph "Server State"
            API[REST API<br/>Database records]
            RT[Real-time<br/>WebSocket updates]
        end
    end

    CL1 -.reads from.-> SS
    CL2 -.reads from.-> SS

    SS <-.persists to.-> LS
    SS <-.persists to.-> IDB

    SS <-.syncs with.-> API
    SS <-.subscribes to.-> RT

    CL1 <-.fetches.-> API
    CL2 <-.fetches.-> API

    style SS fill:#764ba2,color:#fff
    style LS fill:#48bb78,color:#fff
    style IDB fill:#48bb78,color:#fff

Component-Local State Flow

stateDiagram-v2
    [*] --> Initial: constructor()
    Initial --> Rendered: connectedCallback()

    Rendered --> UserAction: User interaction
    UserAction --> UpdateState: this.property = value
    UpdateState --> Render: render()
    Render --> Rendered

    Rendered --> ExternalUpdate: Attribute changed
    ExternalUpdate --> UpdateState

    Rendered --> [*]: disconnectedCallback()

    note right of UpdateState
        • Update instance property
        • No external storage
        • Private to component
    end note

Reactive State with Proxy

sequenceDiagram
    participant Component as Component
    participant Proxy as Reactive Proxy
    participant Listeners as Listeners
    participant UI as UI

    Component->>Proxy: state.count = 42
    Proxy->>Proxy: Intercept set
    Proxy->>Listeners: Notify all listeners
    Listeners->>Component: Trigger callback
    Component->>UI: Re-render

Shared State Pattern

graph TB
    subgraph "Store"
        State["Application State: user, theme, cart"]
        Listeners[Listeners Set]
    end

    subgraph "Components"
        C1[Component 1]
        C2[Component 2]
        C3[Component 3]
    end

    C1 -.subscribe.-> Listeners
    C2 -.subscribe.-> Listeners
    C3 -.subscribe.-> Listeners

    C1 -->|setState| State
    C2 -->|setState| State

    State -.notify.-> Listeners
    Listeners -.trigger.-> C1 & C2 & C3

    style State fill:#764ba2,color:#fff
    style Listeners fill:#667eea,color:#fff

IndexedDB Cache-First Strategy

sequenceDiagram
    participant Component
    participant Memory as Memory Cache
    participant IDB as IndexedDB
    participant API as Backend API

    Component->>Memory: getData(id)
    alt In Memory Cache
        Memory-->>Component: Return cached data
    else Not in Memory
        Component->>IDB: getData(id)
        alt In IndexedDB
            IDB-->>Component: Return cached data
            Component->>Memory: Cache in memory
        else Not in IndexedDB
            Component->>API: fetch('/api/data/' + id)
            API-->>Component: Fresh data
            Component->>IDB: Store in IndexedDB
            Component->>Memory: Cache in memory
        end
    end

    Note over Component,API: Background: Refresh from API
    Component->>API: fetch (background)
    API-->>Component: Latest data
    Component->>IDB: Update IndexedDB
    Component->>Memory: Update memory cache

Offline-First with Sync Queue

graph TB
    subgraph "Client"
        UI[UI Component]
        Local[Local State<br/>IndexedDB]
        Queue[Sync Queue<br/>localStorage]
    end

    subgraph "Network"
        Check{Online?}
    end

    subgraph "Server"
        API[Backend API]
    end

    UI -->|Create/Update/Delete| Local
    Local -.success.-> UI

    Local --> Check

    Check -->|Yes| API
    Check -->|No| Queue

    Queue -.wait for online.-> Check

    API -->|Success| Confirm[Confirm Sync]
    API -->|Error| Queue

    Confirm -.update UI.-> UI

    style Local fill:#48bb78,color:#fff
    style Queue fill:#f59e42,color:#fff
    style API fill:#667eea,color:#fff

State Synchronization Patterns

graph LR
    subgraph "Optimistic Update"
        O1[User Action]
        O2[Update UI Immediately]
        O3[Send to Server]
        O4{Success?}
        O5[Keep Update]
        O6[Rollback]

        O1 --> O2 --> O3 --> O4
        O4 -->|Yes| O5
        O4 -->|No| O6
    end

    subgraph "Pessimistic Update"
        P1[User Action]
        P2[Show Loading]
        P3[Send to Server]
        P4{Success?}
        P5[Update UI]
        P6[Show Error]

        P1 --> P2 --> P3 --> P4
        P4 -->|Yes| P5
        P4 -->|No| P6
    end

    style O2 fill:#48bb78,color:#fff
    style O6 fill:#f56565,color:#fff
    style P5 fill:#48bb78,color:#fff
    style P6 fill:#f56565,color:#fff

pan-store Component Architecture

graph TB
    subgraph "pan-store"
        State[State Object]
        Watchers[Path Watchers<br/>Map&lt;path, handlers&gt;]
        Persist[Persistence Layer]
        Computed[Computed Values]

        State --> Watchers
        State --> Persist
        State --> Computed
    end

    subgraph "Components"
        C1[Component 1]
        C2[Component 2]
        C3[Component 3]
    end

    subgraph "Storage"
        LS[localStorage]
        IDB[IndexedDB]
    end

    C1 -->|setState| State
    C2 -->|setState| State
    C3 -->|getState| State

    Watchers -.notify.-> C1 & C2 & C3

    Persist <-.sync.-> LS & IDB

    style State fill:#764ba2,color:#fff
    style Persist fill:#48bb78,color:#fff

State Update Flow

sequenceDiagram
    participant Component
    participant Store
    participant Middleware
    participant Persistence
    participant PAN as PAN Bus
    participant Subscribers

    Component->>Store: setState({user: newUser})

    Store->>Store: Merge state
    Store->>Middleware: Run middleware
    Middleware->>Middleware: Log state change
    Middleware->>Persistence: Save to localStorage

    Store->>PAN: publish('store.changed')
    PAN->>Subscribers: Notify all subscribers

    Store->>Store: Check watchers
    Store->>Subscribers: Notify path watchers

    Subscribers->>Subscribers: Re-render

Conflict Resolution

graph TB
    Local[Local Update<br/>timestamp: T1]
    Server[Server Update<br/>timestamp: T2]

    Conflict{Conflict?}

    Local --> Conflict
    Server --> Conflict

    Conflict -->|T1 > T2| UseLocal[Use Local<br/>Last Write Wins]
    Conflict -->|T2 > T1| UseServer[Use Server<br/>Last Write Wins]
    Conflict -->|T1 = T2| Merge[Attempt Merge<br/>or Manual Resolution]

    UseLocal --> Sync[Sync to Server]
    UseServer --> Update[Update Local]
    Merge --> Manual[Show Conflict UI]

    style Conflict fill:#f59e42,color:#fff
    style Merge fill:#f56565,color:#fff
    style Sync fill:#48bb78,color:#fff

State Management Decision Tree

graph TB
    Start{Need State?}

    Start -->|Yes| Scope{Share across<br/>components?}

    Scope -->|No| Local[Component-Local State<br/>Instance properties]

    Scope -->|Yes| Persist{Need to<br/>persist?}

    Persist -->|No| Shared[Shared State<br/>Global object or store]

    Persist -->|Yes| Size{Large<br/>dataset?}

    Size -->|No| LS[localStorage<br/>Small data <10MB]
    Size -->|Yes| IDB[IndexedDB<br/>Large data, offline]

    IDB --> Offline{Offline<br/>support?}
    LS --> Offline

    Offline -->|Yes| Queue[Sync Queue<br/>Background sync]
    Offline -->|No| Done[Done]

    Queue --> Done
    Local --> Done
    Shared --> Done

    style Local fill:#667eea,color:#fff
    style Shared fill:#764ba2,color:#fff
    style IDB fill:#48bb78,color:#fff
    style Queue fill:#f59e42,color:#fff