Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Snapshot and Delta Events

Client state depends on a deliberate snapshot-and-delta pattern:

  1. hydrate returns the initial state during audition.
  2. Later handlers emit delta events such as MoveMade or GameEnded.
  3. Client reducers fold deltas into the hydrated state.

Without hydration, a reconnecting UI usually needs a separate imperative fetch path.

Hydrate on connect

export const hydrate = Effect.gen(function* () {
  const room = yield* loadRoom
 
  return {
    roomId: room.id,
    members: room.members,
    messages: room.messages,
  }
})

Delta from handlers

export const sendMessage = RoomActor.handler(
  "SendMessage",
  Effect.fn(function* ({ content }) {
    const message = yield* saveMessage(content)
 
    yield* RoomActor.all.send("MessageAdded", {
      message,
    })
  }),
)

Reduce locally

export const MessageAdded = RoomClient.reducer(
  "MessageAdded",
  ({ message }) =>
    (state) =>
      Effect.succeed({
        ...state,
        messages: [...state.messages, message],
      }),
)

This keeps the client state model hydrated before the UI sees it and event-driven afterward.

Read Lifecycle for hydrate and Client State for the reduction loop.