Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/framework/react/reference/useMutation.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ mutate(variables, {

**Options**

- `mutationFn: (variables: TVariables) => Promise<TData>`
- `mutationFn: (variables: TVariables, context: MutationFunctionContext) => Promise<TData>`
- **Required, but only if no default mutation function has been defined**
- A function that performs an asynchronous task and returns a promise.
- `variables` is an object that `mutate` will pass to your `mutationFn`
- `context` is an object containing the `mutationKey` and the mutation's `meta`
- `gcTime: number | Infinity`
- The time in milliseconds that unused/inactive cache data remains in memory. When a mutation's cache becomes unused or inactive, that cache data will be garbage collected after this duration. When different cache times are specified, the longest one will be used.
- If set to `Infinity`, will disable garbage collection
Expand Down
27 changes: 25 additions & 2 deletions packages/query-core/src/__tests__/mutations.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
import { waitFor } from '@testing-library/react'
import { MutationObserver } from '../mutationObserver'
import { createQueryClient, executeMutation, queryKey, sleep } from './utils'
import type { QueryClient } from '..'
import type { MutationFunctionContext, QueryClient } from '..'
import type { MutationState } from '../mutation'

describe('mutations', () => {
Expand Down Expand Up @@ -49,7 +49,30 @@ describe('mutations', () => {
)

expect(fn).toHaveBeenCalledTimes(1)
expect(fn).toHaveBeenCalledWith('vars')
expect(fn).toHaveBeenCalledWith('vars', expect.anything())
})

test('should provide context to mutationFn', async () => {
const mutationKey = queryKey()
const vars = 'vars' as const
const meta = { a: 1 }
const mutationFn = vi
.fn<[typeof vars, MutationFunctionContext], Promise<'data'>>()
.mockResolvedValue('data')

const mutation = new MutationObserver(queryClient, {
mutationKey,
mutationFn,
meta,
})

await mutation.mutate(vars)

expect(mutationFn).toHaveBeenCalledTimes(1)
const context = mutationFn.mock.calls[0]![1]
expect(context).toBeDefined()
expect(context.mutationKey).toEqual(mutationKey)
expect(context.meta).toEqual(meta)
})

test('mutation should set correct success states', async () => {
Expand Down
7 changes: 6 additions & 1 deletion packages/query-core/src/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Removable } from './removable'
import { createRetryer } from './retryer'
import type {
DefaultError,
MutationFunctionContext,
MutationMeta,
MutationOptions,
MutationStatus,
Expand Down Expand Up @@ -167,7 +168,11 @@ export class Mutation<
if (!this.options.mutationFn) {
return Promise.reject(new Error('No mutationFn found'))
}
return this.options.mutationFn(variables)
const mutationFnContext: MutationFunctionContext = {
mutationKey: this.options.mutationKey,
meta: this.meta,
}
return this.options.mutationFn(variables, mutationFnContext)
},
onFail: (failureCount, error) => {
this.#dispatch({ type: 'failed', failureCount, error })
Expand Down
6 changes: 6 additions & 0 deletions packages/query-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -897,8 +897,14 @@ export type MutationMeta = Register extends {
: Record<string, unknown>
: Record<string, unknown>

export type MutationFunctionContext = {
mutationKey?: MutationKey
meta: MutationMeta | undefined
}

export type MutationFunction<TData = unknown, TVariables = unknown> = (
variables: TVariables,
context: MutationFunctionContext,
) => Promise<TData>

export interface MutationOptions<
Expand Down