React Native Runtimes
Shared state

Locking and revisions

How concurrent writes work, why prefer update over set, and how subscriptions fan out across related paths.

Each path has a native state payload and a revision. Revisions are integers that increment whenever the payload changes:

const messages = chatStore.path<Message[]>('conversations.release-room');

await messages.hydrate();
console.log(messages.getRevision());

Notification fan-out

Subscribers are invalidated for related paths. A subscriber on conversations will be notified when conversations.release-room changes, and a subscriber on conversations.release-room will be notified when conversations changes.

That makes broad subscriptions ("anything under conversations changed") cheap to express, and narrow subscriptions ("messages of one conversation") still update when a parent path is replaced.

Concurrent writers

Prefer one writer per path. If two runtimes can update the same path, use update(...) or a path reducer instead of replacing stale snapshots.

// ❌ Two runtimes race; whichever runs last clobbers the other.
const current = await messages.get();
await messages.set([...current, newMessage]);

// ✅ The native lock guards read-modify-write.
await messages.update(current => [...(current ?? []), newMessage]);

When set is fine

set is correct when the new value doesn't depend on the previous one — for example, setting the current theme, or replacing the full snapshot from a fresh server response.

Reducers via slices

If a store needs a richer write path (typed actions, slice reducers), use the slices option on createSharedStore. See Background thread architecture for a fully wired example with actions, slices, and persistence.

Mental model

  • Path = key in the native C++ store
  • Revision = integer that increments on each write
  • Subscriber = a JS closure tied to a path; the native side calls it when the path or any ancestor changes
  • Lock = scoped to a path; update() holds it for the duration of the reducer

On this page