diff --git a/docs/overview.md b/docs/overview.md index 0f99db210..4aacc577d 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -517,7 +517,11 @@ Transactional mutators allow you to batch and stage local changes across collect Mutators are created with a `mutationFn`. You can define a single, generic `mutationFn` for your whole app. Or you can define collection or mutation specific functions. -The `mutationFn` is responsible for handling the local changes and processing them, usually to send them to a server or database to be stored, e.g.: +The `mutationFn` is responsible for handling the local changes and processing them, usually to send them to a server or database to be stored. + +**Important:** Inside your `mutationFn`, you must ensure that your server writes have synced back before you return, as the optimistic state is dropped when you return from the mutation function. You generally use collection-specific helpers to do this, such as Query's `utils.refetch()`, direct write APIs, or Electric's `utils.awaitTxId()`. + +For example: ```tsx import type { MutationFn } from "@tanstack/react-db" @@ -556,13 +560,19 @@ const addTodo = createOptimisticAction({ completed: false, }) }, - mutationFn: async (text) => { + mutationFn: async (text, params) => { // Persist the todo to your backend const response = await fetch("/api/todos", { method: "POST", body: JSON.stringify({ text, completed: false }), }) - return response.json() + const result = await response.json() + + // IMPORTANT: Ensure server writes have synced back before returning + // This ensures the optimistic state can be safely discarded + await todoCollection.utils.refetch() + + return result }, }) diff --git a/packages/db/src/optimistic-action.ts b/packages/db/src/optimistic-action.ts index 83db572bb..09ad02a15 100644 --- a/packages/db/src/optimistic-action.ts +++ b/packages/db/src/optimistic-action.ts @@ -9,6 +9,11 @@ import type { CreateOptimisticActionsOptions, Transaction } from "./types" * The optimistic update is applied via the `onMutate` callback, and the server mutation * is executed via the `mutationFn`. * + * **Important:** Inside your `mutationFn`, you must ensure that your server writes have synced back + * before you return, as the optimistic state is dropped when you return from the mutation function. + * You generally use collection-specific helpers to do this, such as Query's `utils.refetch()`, + * direct write APIs, or Electric's `utils.awaitTxId()`. + * * @example * ```ts * const addTodo = createOptimisticAction({ @@ -26,7 +31,13 @@ import type { CreateOptimisticActionsOptions, Transaction } from "./types" * method: 'POST', * body: JSON.stringify({ text, completed: false }), * }) - * return response.json() + * const result = await response.json() + * + * // IMPORTANT: Ensure server writes have synced back before returning + * // This ensures the optimistic state can be safely discarded + * await todoCollection.utils.refetch() + * + * return result * } * }) *