Skip to content

Commit 9d66f43

Browse files
committed
fix: prevent state update after mutation unmounted
1 parent 09a6545 commit 9d66f43

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

src/react/tests/useMutation.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,4 +456,24 @@ describe('useMutation', () => {
456456

457457
consoleMock.mockRestore()
458458
})
459+
460+
it('should not change state if unmounted', async () => {
461+
function Mutates() {
462+
const { mutate } = useMutation(() => sleep(10))
463+
return <button onClick={() => mutate()}>mutate</button>
464+
}
465+
function Page() {
466+
const [mounted, setMounted] = React.useState(true)
467+
return (
468+
<div>
469+
<button onClick={() => setMounted(false)}>unmount</button>
470+
{mounted && <Mutates />}
471+
</div>
472+
)
473+
}
474+
475+
const { getByText } = renderWithClient(queryClient, <Page />)
476+
fireEvent.click(getByText('mutate'))
477+
fireEvent.click(getByText('unmount'))
478+
})
459479
})

src/react/useMutation.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ import {
99
UseMutationOptions,
1010
UseMutationResult,
1111
} from './types'
12-
import { MutationFunction, MutationKey } from '../core/types'
12+
import {
13+
MutationFunction,
14+
MutationKey,
15+
MutationObserverResult,
16+
} from '../core/types'
1317

1418
// HOOK
1519

@@ -86,7 +90,19 @@ export function useMutation<
8690

8791
// Subscribe to the observer
8892
React.useEffect(
89-
() => observer.subscribe(notifyManager.batchCalls(setCurrentResult)),
93+
() =>
94+
observer.subscribe(
95+
notifyManager.batchCalls(
96+
(
97+
result: MutationObserverResult<TData, TError, TVariables, TContext>
98+
) => {
99+
// Check if the component is still mounted
100+
if (observer.hasListeners()) {
101+
setCurrentResult(result)
102+
}
103+
}
104+
)
105+
),
90106
[observer]
91107
)
92108

0 commit comments

Comments
 (0)