createMutation primitive. It provides methods to trigger mutations and tracks their state reactively in SolidJS.
Signature
function createMutation<TData, TError, TVariables, TContext>(
options: Accessor<CreateMutationOptions<TData, TError, TVariables, TContext>>,
queryClient?: Accessor<QueryClient>,
): CreateMutationResult<TData, TError, TVariables, TContext>
Parameters
A Solid accessor (function) returning mutation configuration options.
Show properties
Show properties
The function that performs the mutation.
Called before mutation executes. Useful for optimistic updates. Return context value.
Called when mutation succeeds.
Called when mutation fails.
onSettled
(data: TData | undefined, error: TError | null, variables: TVariables, context: TContext | undefined) => void
Called when mutation completes (success or error).
Number of retry attempts or boolean to enable/disable retries.
Delay between retry attempts.
Throw errors instead of setting error state.
Accessor returning a custom QueryClient instance. If not provided, uses the client from context.
Returns
Reactive mutation state and methods.
Show properties
Show properties
Trigger the mutation. Fire-and-forget style (doesn’t return a promise).
Trigger the mutation and return a promise.
The mutation result data.
The error object if the mutation failed.
true when the mutation is currently executing.true when the mutation has succeeded.true when the mutation has failed.true when the mutation is idle (not executing).The current status of the mutation.
The variables passed to the mutation.
Reset the mutation state to initial values.
Type Parameters
TData- Type of data returned by the mutationTError- Type of error (defaults toDefaultError)TVariables- Type of variables passed to the mutation (defaults tovoid)TContext- Type of context returned byonMutate(defaults tounknown)
Examples
Basic Usage
import { createMutation, useQueryClient } from '@tanstack/solid-query'
import { Show } from 'solid-js'
function CreateTodo() {
const queryClient = useQueryClient()
const mutation = createMutation(() => ({
mutationFn: async (newTodo) => {
const res = await fetch('/api/todos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newTodo),
})
return res.json()
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
}))
const handleCreate = () => {
mutation.mutate({ title: 'New Todo', completed: false })
}
return (
<div>
<button onClick={handleCreate} disabled={mutation.isPending}>
{mutation.isPending ? 'Adding...' : 'Add Todo'}
</button>
<Show when={mutation.isError}>
<div>Error: {mutation.error?.message}</div>
</Show>
</div>
)
}
With TypeScript
import { createMutation } from '@tanstack/solid-query'
interface Todo {
id: number
title: string
completed: boolean
}
interface CreateTodoVariables {
title: string
completed: boolean
}
function CreateTodo() {
const mutation = createMutation(() => ({
mutationFn: async (variables: CreateTodoVariables): Promise<Todo> => {
const res = await fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(variables),
})
return res.json()
},
}))
// Type-safe mutation call
const handleCreate = () => {
mutation.mutate({ title: 'Learn Solid Query', completed: false })
}
return <button onClick={handleCreate}>Create</button>
}
Optimistic Updates
import { createMutation, useQueryClient } from '@tanstack/solid-query'
function UpdateTodo() {
const queryClient = useQueryClient()
const mutation = createMutation(() => ({
mutationFn: updateTodo,
onMutate: async (updatedTodo) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: ['todos'] })
// Snapshot previous value
const previousTodos = queryClient.getQueryData(['todos'])
// Optimistically update cache
queryClient.setQueryData(['todos'], (old) => {
return old.map(todo =>
todo.id === updatedTodo.id ? updatedTodo : todo
)
})
// Return context with snapshot
return { previousTodos }
},
onError: (err, updatedTodo, context) => {
// Rollback on error
if (context?.previousTodos) {
queryClient.setQueryData(['todos'], context.previousTodos)
}
},
onSettled: () => {
// Always refetch after error or success
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
}))
return <div>{/* ... */}</div>
}
Using mutateAsync
import { createMutation } from '@tanstack/solid-query'
function CreateTodo() {
const mutation = createMutation(() => ({
mutationFn: createTodo,
}))
const handleSubmit = async () => {
try {
const newTodo = await mutation.mutateAsync({ title: 'New Todo' })
console.log('Created todo:', newTodo)
// Navigate or show success message
} catch (error) {
console.error('Failed to create todo:', error)
}
}
return <button onClick={handleSubmit}>Submit</button>
}
Per-Mutation Callbacks
import { createMutation } from '@tanstack/solid-query'
function CreateTodo() {
const mutation = createMutation(() => ({
mutationFn: createTodo,
}))
const handleCreate = () => {
mutation.mutate(
{ title: 'New Todo' },
{
onSuccess: (data) => {
console.log('Created:', data)
},
onError: (error) => {
console.error('Failed:', error)
},
}
)
}
return <button onClick={handleCreate}>Create</button>
}
Reset Mutation State
import { createMutation } from '@tanstack/solid-query'
import { Show } from 'solid-js'
function CreateTodo() {
const mutation = createMutation(() => ({
mutationFn: createTodo,
}))
const handleCreate = () => {
mutation.reset() // Reset previous state
mutation.mutate({ title: 'New Todo' })
}
return (
<div>
<button onClick={handleCreate}>Create</button>
<Show when={mutation.isSuccess}>
<div>Successfully created!</div>
</Show>
</div>
)
}
Multiple Mutations
import { createMutation, useQueryClient } from '@tanstack/solid-query'
function TodoActions() {
const queryClient = useQueryClient()
const createMutation = createMutation(() => ({
mutationFn: createTodo,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
}))
const deleteMutation = createMutation(() => ({
mutationFn: deleteTodo,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
}))
return (
<div>
<button
onClick={() => createMutation.mutate({ title: 'New' })}
disabled={createMutation.isPending}
>
Create
</button>
<button
onClick={() => deleteMutation.mutate(1)}
disabled={deleteMutation.isPending}
>
Delete
</button>
</div>
)
}
Error Handling with Retry
import { createMutation } from '@tanstack/solid-query'
function CreateTodo() {
const mutation = createMutation(() => ({
mutationFn: createTodo,
retry: 3,
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
onError: (error) => {
console.error('Mutation failed after retries:', error)
},
}))
return <div>{/* ... */}</div>
}
Reactive Mutation Options
import { createSignal, createMemo } from 'solid-js'
import { createMutation } from '@tanstack/solid-query'
function CreateTodo() {
const [shouldRetry, setShouldRetry] = createSignal(true)
const mutationOptions = createMemo(() => ({
mutationFn: createTodo,
retry: shouldRetry() ? 3 : 0,
}))
const mutation = createMutation(mutationOptions)
return <div>{/* ... */}</div>
}
Mutation with Loading State
import { createMutation } from '@tanstack/solid-query'
import { Show, Switch, Match } from 'solid-js'
function CreateTodo() {
const mutation = createMutation(() => ({
mutationFn: createTodo,
}))
return (
<div>
<button onClick={() => mutation.mutate({ title: 'New' })}>
Create Todo
</button>
<Switch>
<Match when={mutation.isPending}>
<div>Creating...</div>
</Match>
<Match when={mutation.isError}>
<div>Error: {mutation.error?.message}</div>
</Match>
<Match when={mutation.isSuccess}>
<div>Todo created successfully!</div>
</Match>
</Switch>
</div>
)
}
Notes
The options parameter must be an accessor (function) to integrate with SolidJS reactivity system.
Use
mutate for fire-and-forget operations and mutateAsync when you need to await the result or handle errors with try/catch.Always invalidate or update relevant queries after a successful mutation to keep your UI in sync with the server state.
Related
- createQuery - For fetching data
- Mutations Guide - Detailed guide on mutations