useMutate
Quick example
Section titled “Quick example”import { useMutate } from '@xnet/react'import { TaskSchema } from './schema'
function AddTaskButton() { const { create, isPending } = useMutate()
return ( <button disabled={isPending} onClick={() => create(TaskSchema, { title: 'New task', status: 'todo' }) } > {isPending ? 'Creating...' : 'Add Task'} </button> )}Signature
Section titled “Signature”function useMutate(): UseMutateResultTakes no parameters. Returns methods for all mutation operations.
Return value
Section titled “Return value”Mutation methods
Section titled “Mutation methods”| Method | Signature | Description |
|---|---|---|
create | (schema, data, id?, options?) => Promise<FlatNode | null> | Create a new node. Returns the created node or null if store isn’t ready. |
update | (schema, id, data, options?) => Promise<FlatNode | null> | Update properties. Only changed fields are written. |
remove | (id, options?) => Promise<void> | Soft-delete a node. Recoverable via restore. |
restore | (id, options?) => Promise<FlatNode | null> | Restore a soft-deleted node. |
mutate | (ops[], options?) => Promise<TransactionResult | null> | Batch multiple operations atomically. |
Status fields
Section titled “Status fields”| Field | Type | Description |
|---|---|---|
isPending | boolean | true if any mutation is currently in flight. |
pendingCount | number | Number of concurrent mutations in flight. |
MutateOptions
Section titled “MutateOptions”| Field | Type | Default | Description |
|---|---|---|---|
optimistic | boolean | true | Whether to apply optimistic updates. Currently accepted but unused — all writes go directly to the store. |
Usage patterns
Section titled “Usage patterns”Basic CRUD
Section titled “Basic CRUD”const { create, update, remove, restore } = useMutate()
// Createconst task = await create(TaskSchema, { title: 'Ship v1', status: 'todo'})
// Update (sparse — only changed fields)await update(TaskSchema, task.id, { status: 'doing' })
// Soft-deleteawait remove(task.id)
// Restoreawait restore(task.id)Custom ID
Section titled “Custom ID”Pass an optional third argument to create to specify the node ID:
const task = await create(TaskSchema, { title: 'Known ID' }, 'my-custom-id')// task.id === 'my-custom-id'Transactions (batch operations)
Section titled “Transactions (batch operations)”Use mutate() to execute multiple operations atomically:
const { mutate } = useMutate()
const result = await mutate([ { type: 'create', schema: TaskSchema, data: { title: 'Task A' } }, { type: 'create', schema: TaskSchema, data: { title: 'Task B' } }, { type: 'update', id: existingId, data: { status: 'done' } }, { type: 'delete', id: oldTaskId }])Transactions with temp IDs
Section titled “Transactions with temp IDs”When creating related nodes in a transaction, the result includes a tempIds map from your provided IDs to the generated real IDs:
const result = await mutate([ { type: 'create', schema: ProjectSchema, data: { title: 'New Project' }, id: 'temp-project' }, { type: 'create', schema: TaskSchema, data: { title: 'First task', projectId: 'temp-project' // Reference the temp ID } }])
// result.tempIds['temp-project'] → real generated IDTransactionResult
Section titled “TransactionResult”interface TransactionResult { batchId: string // Unique batch identifier results: (NodeState | null)[] // One result per operation (null for deletes) changes: NodeChange[] // All changes produced tempIds: Record<string, string> // Temp ID → real ID mapping}Form integration
Section titled “Form integration”function TaskForm({ taskId }: { taskId: string }) { const { data: task } = useQuery(TaskSchema, taskId) const { update } = useMutate() const [title, setTitle] = useState('')
useEffect(() => { if (task) setTitle(task.title) }, [task])
const save = () => update(TaskSchema, taskId, { title })
return ( <form onSubmit={(e) => { e.preventDefault() save() }} > <input value={title} onChange={(e) => setTitle(e.target.value)} /> <button type="submit">Save</button> </form> )}Tracking pending state
Section titled “Tracking pending state”const { create, isPending, pendingCount } = useMutate()
// Disable UI during mutations<button disabled={isPending}>Save</button>
// Show count for batch operations{pendingCount > 0 && <span>{pendingCount} operations pending...</span>}Gotchas
Section titled “Gotchas”Related
Section titled “Related”useQuery— read the data you mutateuseNode— alternative for single-node editing with YjsdefineSchema— define the schemas you write to