From 695d32b684763245b175a42b0aac136c17aaccb6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Feb 2026 12:14:09 +0000 Subject: [PATCH 1/2] docs: clarify multiple pending transactions layering behavior Adds a subsection to Mutation Lifecycle explaining how multiple optimistic updates to the same item are layered, with the most recent transaction taking priority for display state. https://claude.ai/code/session_01HruHi63EH2HhdQy86tWteX --- docs/guides/mutations.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/guides/mutations.md b/docs/guides/mutations.md index b3f698084..b8c38aafa 100644 --- a/docs/guides/mutations.md +++ b/docs/guides/mutations.md @@ -261,6 +261,27 @@ todoCollection.update(todo.id, (draft) => { If the handler throws an error during persistence, the optimistic state is automatically rolled back. +### Multiple Pending Transactions + +When you make multiple mutations to the same item before earlier ones have synced back, each mutation creates a separate transaction. These transactions are **layered**, with the most recent transaction's state taking priority for display. + +```tsx +// User rapidly updates a document's content: A → B → C +docCollection.update(docId, (draft) => { draft.content = "A" }) // tx1 +docCollection.update(docId, (draft) => { draft.content = "B" }) // tx2 +docCollection.update(docId, (draft) => { draft.content = "C" }) // tx3 + +// Visible state = "C" (latest transaction wins) +``` + +As each transaction syncs back from the server, the optimistic state is **recomputed** from the remaining pending transactions. This means your latest changes are preserved: + +- When tx1 syncs back → tx2 and tx3 still pending → visible state remains "C" +- When tx2 syncs back → tx3 still pending → visible state remains "C" +- When tx3 syncs back → no pending transactions → visible state = synced server state + +This layering ensures that rapid sequential updates feel instant and consistent, without earlier sync confirmations disrupting the user's most recent changes. + ## Collection Write Operations Collections support three core write operations: `insert`, `update`, and `delete`. Each operation applies optimistic state immediately and triggers the corresponding operation handler. From 1bd5cc1bdf1d4f41f2137f2be27ea9feb488d282 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Feb 2026 13:06:08 +0000 Subject: [PATCH 2/2] docs: add cross-transaction optimistic state visibility details Clarifies that: - Optimistic layering operates at the item level, not individual fields - The draft in update() reflects all pending optimistic changes from all transactions, enabling mutations to build on each other https://claude.ai/code/session_01HruHi63EH2HhdQy86tWteX --- docs/guides/mutations.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/guides/mutations.md b/docs/guides/mutations.md index b8c38aafa..c72adc7d6 100644 --- a/docs/guides/mutations.md +++ b/docs/guides/mutations.md @@ -263,7 +263,7 @@ If the handler throws an error during persistence, the optimistic state is autom ### Multiple Pending Transactions -When you make multiple mutations to the same item before earlier ones have synced back, each mutation creates a separate transaction. These transactions are **layered**, with the most recent transaction's state taking priority for display. +When you make multiple mutations to the same item before earlier ones have synced back, each mutation creates a separate transaction. These transactions are **layered**, with the most recent transaction's state taking priority for display. Layering operates at the item level—the entire item is overlaid, not individual fields within it. ```tsx // User rapidly updates a document's content: A → B → C @@ -282,6 +282,28 @@ As each transaction syncs back from the server, the optimistic state is **recomp This layering ensures that rapid sequential updates feel instant and consistent, without earlier sync confirmations disrupting the user's most recent changes. +When you call `update()`, the draft reflects the **current visible state**, which includes optimistic changes from all pending transactions—not just your own. This means mutations build on top of each other: + +```tsx +const tx1 = createTransaction({ mutationFn, autoCommit: false }) +const tx2 = createTransaction({ mutationFn, autoCommit: false }) + +tx1.mutate(() => { + itemCollection.update("A", (draft) => { draft.value = 1 }) +}) + +tx2.mutate(() => { + itemCollection.update("B", (draft) => { draft.value = 2 }) +}) + +tx1.mutate(() => { + // draft.value here is 2 (from tx2), not the original synced value + itemCollection.update("B", (draft) => { draft.value = draft.value + 10 }) +}) + +// Visible state: A=1, B=12 +``` + ## Collection Write Operations Collections support three core write operations: `insert`, `update`, and `delete`. Each operation applies optimistic state immediately and triggers the corresponding operation handler.