UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

1 lines 3.54 kB
{"version":3,"file":"optimistic-action.cjs","sources":["../../src/optimistic-action.ts"],"sourcesContent":["import { createTransaction } from './transactions'\nimport { OnMutateMustBeSynchronousError } from './errors'\nimport { isPromiseLike } from './utils/type-guards'\nimport type { CreateOptimisticActionsOptions, Transaction } from './types'\n\n/**\n * Creates an optimistic action function that applies local optimistic updates immediately\n * before executing the actual mutation on the server.\n *\n * This pattern allows for responsive UI updates while the actual mutation is in progress.\n * The optimistic update is applied via the `onMutate` callback, and the server mutation\n * is executed via the `mutationFn`.\n *\n * **Important:** Inside your `mutationFn`, you must ensure that your server writes have synced back\n * before you return, as the optimistic state is dropped when you return from the mutation function.\n * You generally use collection-specific helpers to do this, such as Query's `utils.refetch()`,\n * direct write APIs, or Electric's `utils.awaitTxId()`.\n *\n * @example\n * ```ts\n * const addTodo = createOptimisticAction<string>({\n * onMutate: (text) => {\n * // Instantly applies local optimistic state\n * todoCollection.insert({\n * id: uuid(),\n * text,\n * completed: false\n * })\n * },\n * mutationFn: async (text, params) => {\n * // Persist the todo to your backend\n * const response = await fetch('/api/todos', {\n * method: 'POST',\n * body: JSON.stringify({ text, completed: false }),\n * })\n * const result = await response.json()\n *\n * // IMPORTANT: Ensure server writes have synced back before returning\n * // This ensures the optimistic state can be safely discarded\n * await todoCollection.utils.refetch()\n *\n * return result\n * }\n * })\n *\n * // Usage\n * const transaction = addTodo('New Todo Item')\n * ```\n *\n * @template TVariables - The type of variables that will be passed to the action function\n * @param options - Configuration options for the optimistic action\n * @returns A function that accepts variables of type TVariables and returns a Transaction\n */\nexport function createOptimisticAction<TVariables = unknown>(\n options: CreateOptimisticActionsOptions<TVariables>,\n) {\n const { mutationFn, onMutate, ...config } = options\n\n return (variables: TVariables): Transaction => {\n // Create transaction with the original config\n const transaction = createTransaction({\n ...config,\n // Wire the mutationFn to use the provided variables\n mutationFn: async (params) => {\n return await mutationFn(variables, params)\n },\n })\n\n // Execute the transaction. The mutationFn is called once mutate()\n // is finished.\n transaction.mutate(() => {\n const maybePromise = onMutate(variables) as unknown\n\n if (isPromiseLike(maybePromise)) {\n throw new OnMutateMustBeSynchronousError()\n }\n })\n\n return transaction\n }\n}\n"],"names":["createTransaction","isPromiseLike","OnMutateMustBeSynchronousError"],"mappings":";;;;;AAqDO,SAAS,uBACd,SACA;AACA,QAAM,EAAE,YAAY,UAAU,GAAG,WAAW;AAE5C,SAAO,CAAC,cAAuC;AAE7C,UAAM,cAAcA,aAAAA,kBAAkB;AAAA,MACpC,GAAG;AAAA;AAAA,MAEH,YAAY,OAAO,WAAW;AAC5B,eAAO,MAAM,WAAW,WAAW,MAAM;AAAA,MAC3C;AAAA,IAAA,CACD;AAID,gBAAY,OAAO,MAAM;AACvB,YAAM,eAAe,SAAS,SAAS;AAEvC,UAAIC,WAAAA,cAAc,YAAY,GAAG;AAC/B,cAAM,IAAIC,OAAAA,+BAAA;AAAA,MACZ;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AACF;;"}