--- id: mutations title: Mutations ref: docs/framework/react/guides/mutations.md replace: { 'hook': 'function' } --- [//]: # 'Example' ```tsx import { Switch, Match, Show } from 'solid-js' function App() { const mutation = useMutation(() => ({ mutationFn: (newTodo) => { return axios.post('/todos', newTodo) }, })) return (
Adding todo...
An error occurred: {mutation.error.message}
Todo added!
) } ``` [//]: # 'Example' [//]: # 'Info1' [//]: # 'Info1' [//]: # 'Example2' ```tsx const CreateTodo = () => { const mutation = useMutation(() => ({ mutationFn: (formData) => { return fetch('/api', formData) }, })) const onSubmit = (event) => { event.preventDefault() mutation.mutate(new FormData(event.target)) } return
...
} ``` [//]: # 'Example2' [//]: # 'Example3' ```tsx import { createSignal, Show } from 'solid-js' const CreateTodo = () => { const [title, setTitle] = createSignal('') const mutation = useMutation(() => ({ mutationFn: createTodo })) const onCreateTodo = (e) => { e.preventDefault() mutation.mutate({ title: title() }) } return (
mutation.reset()}>{mutation.error}
setTitle(e.currentTarget.value)} />
) } ``` [//]: # 'Example3' [//]: # 'Example4' ```tsx useMutation(() => ({ mutationFn: addTodo, onMutate: (variables, context) => { // A mutation is about to happen! // Optionally return a result containing data to use when for example rolling back return { id: 1 } }, onError: (error, variables, onMutateResult, context) => { // An error happened! console.log(`rolling back optimistic update with id ${onMutateResult.id}`) }, onSuccess: (data, variables, onMutateResult, context) => { // Boom baby! }, onSettled: (data, error, variables, onMutateResult, context) => { // Error or success... doesn't matter! }, })) ``` [//]: # 'Example4' [//]: # 'Example5' ```tsx useMutation(() => ({ mutationFn: addTodo, onSuccess: async () => { console.log("I'm first!") }, onSettled: async () => { console.log("I'm second!") }, })) ``` [//]: # 'Example5' [//]: # 'Example6' ```tsx useMutation(() => ({ mutationFn: addTodo, onSuccess: (data, variables, onMutateResult, context) => { // I will fire first }, onError: (error, variables, onMutateResult, context) => { // I will fire first }, onSettled: (data, error, variables, onMutateResult, context) => { // I will fire first }, })) mutate(todo, { onSuccess: (data, variables, onMutateResult, context) => { // I will fire second! }, onError: (error, variables, onMutateResult, context) => { // I will fire second! }, onSettled: (data, error, variables, onMutateResult, context) => { // I will fire second! }, }) ``` [//]: # 'Example6' [//]: # 'Example7' ```tsx useMutation(() => ({ mutationFn: addTodo, onSuccess: (data, variables, onMutateResult, context) => { // Will be called 3 times }, })) const todos = ['Todo 1', 'Todo 2', 'Todo 3'] todos.forEach((todo) => { mutate(todo, { onSuccess: (data, variables, onMutateResult, context) => { // Will execute only once, for the last mutation (Todo 3), // regardless which mutation resolves first }, }) }) ``` [//]: # 'Example7' [//]: # 'Example8' ```tsx const mutation = useMutation(() => ({ mutationFn: addTodo })) try { const todo = await mutation.mutateAsync(todo) console.log(todo) } catch (error) { console.error(error) } finally { console.log('done') } ``` [//]: # 'Example8' [//]: # 'Example9' ```tsx const mutation = useMutation(() => ({ mutationFn: addTodo, retry: 3, })) ``` [//]: # 'Example9' [//]: # 'Example10' ```tsx const queryClient = new QueryClient() // Define the "addTodo" mutation queryClient.setMutationDefaults(['addTodo'], { mutationFn: addTodo, onMutate: async (variables, context) => { // Cancel current queries for the todos list await context.client.cancelQueries({ queryKey: ['todos'] }) // Create optimistic todo const optimisticTodo = { id: uuid(), title: variables.title } // Add optimistic todo to todos list context.client.setQueryData(['todos'], (old) => [...old, optimisticTodo]) // Return a result with the optimistic todo return { optimisticTodo } }, onSuccess: (result, variables, onMutateResult, context) => { // Replace optimistic todo in the todos list with the result context.client.setQueryData(['todos'], (old) => old.map((todo) => todo.id === onMutateResult.optimisticTodo.id ? result : todo, ), ) }, onError: (error, variables, onMutateResult, context) => { // Remove optimistic todo from the todos list context.client.setQueryData(['todos'], (old) => old.filter((todo) => todo.id !== onMutateResult.optimisticTodo.id), ) }, retry: 3, }) // Start mutation in some component: const mutation = useMutation(() => ({ mutationKey: ['addTodo'] })) mutation.mutate({ title: 'title' }) // If the mutation has been paused because the device is for example offline, // Then the paused mutation can be dehydrated when the application quits: const state = dehydrate(queryClient) // The mutation can then be hydrated again when the application is started: hydrate(queryClient, state) // Resume the paused mutations: queryClient.resumePausedMutations() ``` [//]: # 'Example10' [//]: # 'PersistOfflineIntro' ### Persisting Offline mutations If you persist offline mutations with the `persistQueryClient` plugin, mutations cannot be resumed when the page is reloaded unless you provide a default mutation function. [//]: # 'PersistOfflineIntro' [//]: # 'OfflineExampleLink' [//]: # 'OfflineExampleLink' [//]: # 'ExampleScopes' ```tsx const mutation = useMutation(() => ({ mutationFn: addTodo, scope: { id: 'todo', }, })) ``` [//]: # 'ExampleScopes' [//]: # 'Materials' ## Further reading For more information about mutations, have a look at [TkDodo's article on Mastering Mutations in TanStack Query](https://tkdodo.eu/blog/mastering-mutations-in-react-query). [//]: # 'Materials'