Skip to content

Commit 006ce1a

Browse files
authored
feat(react-query): backport mutationOptions (#10368)
1 parent 430bdd0 commit 006ce1a

5 files changed

Lines changed: 618 additions & 0 deletions

File tree

.changeset/icy-cities-speak.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/react-query': minor
3+
---
4+
5+
feat(react-query): backport mutationOptions in v4
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import * as React from 'react'
2+
import { QueryClient } from '@tanstack/query-core'
3+
import { fireEvent, waitFor } from '@testing-library/react'
4+
import { mutationOptions } from '../mutationOptions'
5+
import { useIsMutating, useMutation } from '..'
6+
import { renderWithClient, sleep } from './utils'
7+
import type { UseMutationOptions } from '../types'
8+
9+
describe('mutationOptions', () => {
10+
it('should return the object received as a parameter without any modification (with mutationKey)', () => {
11+
const object: UseMutationOptions = {
12+
mutationKey: ['key'],
13+
mutationFn: () => Promise.resolve(5),
14+
} as const
15+
16+
expect(mutationOptions(object)).toBe(object)
17+
})
18+
19+
it('should return the object received as a parameter without any modification (without mutationKey)', () => {
20+
const object: UseMutationOptions = {
21+
mutationFn: () => Promise.resolve(5),
22+
} as const
23+
24+
expect(mutationOptions(object)).toBe(object)
25+
})
26+
27+
it('should work with useMutation (with mutationKey)', async () => {
28+
const queryClient = new QueryClient()
29+
const mutationOpts = mutationOptions({
30+
mutationKey: ['key'],
31+
mutationFn: () => sleep(10).then(() => 'data'),
32+
})
33+
34+
function Page() {
35+
const mutation = useMutation(mutationOpts)
36+
37+
return (
38+
<div>
39+
<button onClick={() => mutation.mutate()}>mutate</button>
40+
<span>{mutation.data ?? 'empty'}</span>
41+
</div>
42+
)
43+
}
44+
45+
const rendered = renderWithClient(queryClient, <Page />)
46+
47+
expect(rendered.getByText('empty')).toBeTruthy()
48+
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
49+
await waitFor(() => rendered.getByText('data'))
50+
})
51+
52+
it('should work with useMutation (without mutationKey)', async () => {
53+
const queryClient = new QueryClient()
54+
const mutationOpts = mutationOptions({
55+
mutationFn: () => sleep(10).then(() => 'data'),
56+
})
57+
58+
function Page() {
59+
const mutation = useMutation(mutationOpts)
60+
61+
return (
62+
<div>
63+
<button onClick={() => mutation.mutate()}>mutate</button>
64+
<span>{mutation.data ?? 'empty'}</span>
65+
</div>
66+
)
67+
}
68+
69+
const rendered = renderWithClient(queryClient, <Page />)
70+
71+
expect(rendered.getByText('empty')).toBeTruthy()
72+
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
73+
await waitFor(() => rendered.getByText('data'))
74+
})
75+
76+
it('should work with useIsMutating filtering by mutationKey', async () => {
77+
const queryClient = new QueryClient()
78+
const mutationOpts1 = mutationOptions({
79+
mutationKey: ['key1'],
80+
mutationFn: () => sleep(50).then(() => 'data1'),
81+
})
82+
const mutationOpts2 = mutationOptions({
83+
mutationKey: ['key2'],
84+
mutationFn: () => sleep(50).then(() => 'data2'),
85+
})
86+
87+
function Page() {
88+
const isMutating = useIsMutating({
89+
mutationKey: mutationOpts1.mutationKey,
90+
})
91+
const { mutate: mutate1 } = useMutation(mutationOpts1)
92+
const { mutate: mutate2 } = useMutation(mutationOpts2)
93+
94+
return (
95+
<div>
96+
<span>isMutating: {isMutating}</span>
97+
<button onClick={() => mutate1()}>mutate1</button>
98+
<button onClick={() => mutate2()}>mutate2</button>
99+
</div>
100+
)
101+
}
102+
103+
const rendered = renderWithClient(queryClient, <Page />)
104+
105+
rendered.getByText('isMutating: 0')
106+
fireEvent.click(rendered.getByRole('button', { name: /mutate1/i }))
107+
fireEvent.click(rendered.getByRole('button', { name: /mutate2/i }))
108+
await waitFor(() => rendered.getByText('isMutating: 1'))
109+
await waitFor(() => rendered.getByText('isMutating: 0'))
110+
})
111+
112+
it('should work with queryClient.isMutating', async () => {
113+
const queryClient = new QueryClient()
114+
const mutationOpts = mutationOptions({
115+
mutationKey: ['mutation'],
116+
mutationFn: () => sleep(10).then(() => 'data'),
117+
})
118+
119+
function Page() {
120+
const isMutating = queryClient.isMutating({
121+
mutationKey: mutationOpts.mutationKey,
122+
})
123+
const { mutate } = useMutation(mutationOpts)
124+
125+
return (
126+
<div>
127+
<span>isMutating: {isMutating}</span>
128+
<button onClick={() => mutate()}>mutate</button>
129+
</div>
130+
)
131+
}
132+
133+
const rendered = renderWithClient(queryClient, <Page />)
134+
135+
rendered.getByText('isMutating: 0')
136+
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
137+
await waitFor(() => rendered.getByText('isMutating: 1'))
138+
await waitFor(() => rendered.getByText('isMutating: 0'))
139+
})
140+
})

0 commit comments

Comments
 (0)