--- id: optimistic-updates title: Optimistic Updates ref: docs/framework/react/guides/optimistic-updates.md replace: { 'React Query': 'Solid Query', 'hook': 'function' } --- [//]: # 'ExampleUI1' ```tsx const addTodoMutation = useMutation(() => ({ mutationFn: (newTodo: string) => axios.post('/api/data', { text: newTodo }), // make sure to _return_ the Promise from the query invalidation // so that the mutation stays in `pending` state until the refetch is finished onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }), })) ``` [//]: # 'ExampleUI1' [//]: # 'ExampleUI2' ```tsx ``` [//]: # 'ExampleUI2' [//]: # 'ExampleUI3' ```tsx
  • {addTodoMutation.variables}
  • ``` [//]: # 'ExampleUI3' [//]: # 'ExampleUI4' ```tsx // somewhere in your app const mutation = useMutation(() => ({ mutationFn: (newTodo: string) => axios.post('/api/data', { text: newTodo }), onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }), mutationKey: ['addTodo'], })) // access variables somewhere else const variables = useMutationState(() => ({ filters: { mutationKey: ['addTodo'], status: 'pending' }, select: (mutation) => mutation.state.variables, })) ``` [//]: # 'ExampleUI4' [//]: # 'Example' ```tsx const queryClient = useQueryClient() useMutation(() => ({ mutationFn: updateTodo, // When mutate is called: onMutate: async (newTodo, context) => { // Cancel any outgoing refetches // (so they don't overwrite our optimistic update) await context.client.cancelQueries({ queryKey: ['todos'] }) // Snapshot the previous value const previousTodos = context.client.getQueryData(['todos']) // Optimistically update to the new value context.client.setQueryData(['todos'], (old) => [...old, newTodo]) // Return a result with the snapshotted value return { previousTodos } }, // If the mutation fails, // use the result returned from onMutate to roll back onError: (err, newTodo, onMutateResult, context) => { context.client.setQueryData(['todos'], onMutateResult.previousTodos) }, // Always refetch after error or success: onSettled: (data, error, variables, onMutateResult, context) => context.client.invalidateQueries({ queryKey: ['todos'] }), })) ``` [//]: # 'Example' [//]: # 'Example2' ```tsx useMutation(() => ({ mutationFn: updateTodo, // When mutate is called: onMutate: async (newTodo, context) => { // Cancel any outgoing refetches // (so they don't overwrite our optimistic update) await context.client.cancelQueries({ queryKey: ['todos', newTodo.id] }) // Snapshot the previous value const previousTodo = context.client.getQueryData(['todos', newTodo.id]) // Optimistically update to the new value context.client.setQueryData(['todos', newTodo.id], newTodo) // Return a result with the previous and new todo return { previousTodo, newTodo } }, // If the mutation fails, use the result we returned above onError: (err, newTodo, onMutateResult, context) => { context.client.setQueryData( ['todos', onMutateResult.newTodo.id], onMutateResult.previousTodo, ) }, // Always refetch after error or success: onSettled: (newTodo, error, variables, onMutateResult, context) => context.client.invalidateQueries({ queryKey: ['todos', newTodo.id] }), })) ``` [//]: # 'Example2' [//]: # 'Example3' ```tsx useMutation(() => ({ mutationFn: updateTodo, // ... onSettled: async (newTodo, error, variables, onMutateResult, context) => { if (error) { // do something } }, })) ``` [//]: # 'Example3'