Skip to content

Commit 98b9d9b

Browse files
authored
🐛 Fix bug with useMutation shared results (#1616)
1 parent 762ee8a commit 98b9d9b

File tree

2 files changed

+86
-10
lines changed

2 files changed

+86
-10
lines changed

packages/toolkit/src/query/react/buildHooks.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -825,16 +825,19 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
825825
const originalArgs =
826826
fixedCacheKey == null ? promise?.arg.originalArgs : undefined
827827
const reset = useCallback(() => {
828-
if (promise) {
829-
setPromise(undefined)
830-
} else if (fixedCacheKey) {
831-
dispatch(
832-
api.internalActions.removeMutationResult({
833-
requestId,
834-
fixedCacheKey,
835-
})
836-
)
837-
}
828+
batch(() => {
829+
if (promise) {
830+
setPromise(undefined)
831+
}
832+
if (fixedCacheKey) {
833+
dispatch(
834+
api.internalActions.removeMutationResult({
835+
requestId,
836+
fixedCacheKey,
837+
})
838+
)
839+
}
840+
})
838841
}, [dispatch, fixedCacheKey, promise, requestId])
839842
const finalState = useMemo(
840843
() => ({ ...currentState, originalArgs, reset }),

packages/toolkit/src/query/tests/useMutation-fixedCacheKey.test.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,79 @@ describe('fixedCacheKey', () => {
9494
expect(getByTestId(c2, 'data').textContent).toBe('')
9595
})
9696

97+
test('resetting from the component that triggered the mutation resets for each shared result', async () => {
98+
render(
99+
<>
100+
<Component name="C1" fixedCacheKey="test-A" />
101+
<Component name="C2" fixedCacheKey="test-A" />
102+
<Component name="C3" fixedCacheKey="test-B" />
103+
<Component name="C4" fixedCacheKey="test-B" />
104+
</>,
105+
{ wrapper: storeRef.wrapper }
106+
)
107+
const c1 = screen.getByTestId('C1')
108+
const c2 = screen.getByTestId('C2')
109+
const c3 = screen.getByTestId('C3')
110+
const c4 = screen.getByTestId('C4')
111+
expect(getByTestId(c1, 'status').textContent).toBe('uninitialized')
112+
expect(getByTestId(c2, 'status').textContent).toBe('uninitialized')
113+
expect(getByTestId(c3, 'status').textContent).toBe('uninitialized')
114+
expect(getByTestId(c4, 'status').textContent).toBe('uninitialized')
115+
116+
// trigger with a component using the first cache key
117+
getByTestId(c1, 'trigger').click()
118+
119+
await waitFor(() =>
120+
expect(getByTestId(c1, 'status').textContent).toBe('fulfilled')
121+
)
122+
123+
// the components with the first cache key should be affected
124+
expect(getByTestId(c1, 'data').textContent).toBe('C1')
125+
expect(getByTestId(c2, 'status').textContent).toBe('fulfilled')
126+
expect(getByTestId(c2, 'data').textContent).toBe('C1')
127+
expect(getByTestId(c2, 'status').textContent).toBe('fulfilled')
128+
129+
// the components with the second cache key should be unaffected
130+
expect(getByTestId(c3, 'data').textContent).toBe('')
131+
expect(getByTestId(c3, 'status').textContent).toBe('uninitialized')
132+
expect(getByTestId(c4, 'data').textContent).toBe('')
133+
expect(getByTestId(c4, 'status').textContent).toBe('uninitialized')
134+
135+
// trigger with a component using the second cache key
136+
getByTestId(c3, 'trigger').click()
137+
138+
await waitFor(() =>
139+
expect(getByTestId(c3, 'status').textContent).toBe('fulfilled')
140+
)
141+
142+
// the components with the first cache key should be unaffected
143+
expect(getByTestId(c1, 'data').textContent).toBe('C1')
144+
expect(getByTestId(c2, 'status').textContent).toBe('fulfilled')
145+
expect(getByTestId(c2, 'data').textContent).toBe('C1')
146+
expect(getByTestId(c2, 'status').textContent).toBe('fulfilled')
147+
148+
// the component with the second cache key should be affected
149+
expect(getByTestId(c3, 'data').textContent).toBe('C3')
150+
expect(getByTestId(c3, 'status').textContent).toBe('fulfilled')
151+
expect(getByTestId(c4, 'data').textContent).toBe('C3')
152+
expect(getByTestId(c4, 'status').textContent).toBe('fulfilled')
153+
154+
// test reset from the component that triggered the mutation for the first cache key
155+
getByTestId(c1, 'reset').click()
156+
157+
// the components with the first cache key should be affected
158+
expect(getByTestId(c1, 'data').textContent).toBe('')
159+
expect(getByTestId(c1, 'status').textContent).toBe('uninitialized')
160+
expect(getByTestId(c2, 'data').textContent).toBe('')
161+
expect(getByTestId(c2, 'status').textContent).toBe('uninitialized')
162+
163+
// the components with the second cache key should be unaffected
164+
expect(getByTestId(c3, 'data').textContent).toBe('C3')
165+
expect(getByTestId(c3, 'status').textContent).toBe('fulfilled')
166+
expect(getByTestId(c4, 'data').textContent).toBe('C3')
167+
expect(getByTestId(c4, 'status').textContent).toBe('fulfilled')
168+
})
169+
97170
test('two mutations with different `fixedCacheKey` do not influence each other', async () => {
98171
render(
99172
<>

0 commit comments

Comments
 (0)