State Store
Each actor handle has an internal StateStore that manages the client-side copy of the actor’s state.
How It Works
Section titled “How It Works”- When you call
handle.state.subscribe(), the client sends astate:submessage - The server responds with a
state:snapshotcontaining the full state - On each state change, the server sends
state:patchwith JSON Patch operations - The
StateStoreapplies patches to its local copy and notifies subscribers
StateStore API
Section titled “StateStore API”class StateStore<TState> { getState(): TState | undefined; setSnapshot(state: TState): void; applyPatches(patches: JsonPatchOp[]): void; subscribe(listener: (state: TState) => void): Unsubscribe; get subscriberCount(): number;}The StateStore is internal to actor handles — you interact with it through the handle’s .state property, not directly.
JSON Patch Support
Section titled “JSON Patch Support”The store implements a subset of RFC 6902:
| Operation | Description |
|---|---|
add | Add a value at a path (including array append with -) |
replace | Replace the value at a path |
remove | Remove the value at a path |
Path Syntax
Section titled “Path Syntax”Paths follow JSON Pointer syntax (RFC 6901):
/messages/0/text → state.messages[0].text/players/- → append to state.players array/count → state.countSpecial characters are escaped: ~0 for ~, ~1 for /.
Immutability
Section titled “Immutability”Patches are applied using structuredClone() — each update produces a new state object. This ensures React’s useSyncExternalStore detects changes correctly.
Subscriber Notification
Section titled “Subscriber Notification”Subscribers are called synchronously after each state update (snapshot or patch). If state is undefined (no snapshot received yet), subscribers are not called.
When a new subscriber is added and state is already available, the subscriber is called immediately with the current state.
Integration with React
Section titled “Integration with React”The useActorState hook from @zocket/react is built on top of StateStore:
// Subscribes to the store, re-renders on changesconst messages = useActorState(room, (s) => s.messages);See React Hooks for details on selectors and memoization.