diff --git a/.changeset/yellow-fans-move.md b/.changeset/yellow-fans-move.md
new file mode 100644
index 00000000000..936ec8a859c
--- /dev/null
+++ b/.changeset/yellow-fans-move.md
@@ -0,0 +1,5 @@
+---
+"@apollo/client": patch
+---
+
+`useMutation`: also reset internal state on reset
diff --git a/.size-limit.cjs b/.size-limit.cjs
index d63784ccf10..0ab7c9f0aef 100644
--- a/.size-limit.cjs
+++ b/.size-limit.cjs
@@ -1,7 +1,7 @@
const checks = [
{
path: "dist/apollo-client.min.cjs",
- limit: "37956",
+ limit: "37972",
},
{
path: "dist/main.cjs",
diff --git a/src/react/hooks/__tests__/useMutation.test.tsx b/src/react/hooks/__tests__/useMutation.test.tsx
index 3ba88663d85..45619b63b68 100644
--- a/src/react/hooks/__tests__/useMutation.test.tsx
+++ b/src/react/hooks/__tests__/useMutation.test.tsx
@@ -23,13 +23,14 @@ import {
MockSubscriptionLink,
mockSingleLink,
subscribeAndCount,
+ MockedResponse,
} from "../../../testing";
import { ApolloProvider } from "../../context";
import { useQuery } from "../useQuery";
import { useMutation } from "../useMutation";
import { BatchHttpLink } from "../../../link/batch-http";
import { FetchResult } from "../../../link/core";
-import { spyOnConsole } from "../../../testing/internal";
+import { profileHook, spyOnConsole } from "../../../testing/internal";
describe("useMutation Hook", () => {
interface Todo {
@@ -719,6 +720,90 @@ describe("useMutation Hook", () => {
{ interval: 1 }
);
});
+
+ it("resetting while a mutation is running: ensure that the result doesn't end up in the hook", async () => {
+ const CREATE_TODO_DATA = {
+ createTodo: {
+ id: 1,
+ priority: "Low",
+ description: "Get milk!",
+ __typename: "Todo",
+ },
+ };
+
+ const mocks: MockedResponse[] = [
+ {
+ request: {
+ query: CREATE_TODO_MUTATION,
+ variables: {
+ priority: "Low",
+ description: "Get milk.",
+ },
+ },
+ result: {
+ data: CREATE_TODO_DATA,
+ },
+ delay: 20,
+ },
+ ];
+
+ const ProfiledHook = profileHook(() =>
+ useMutation<
+ { createTodo: Todo },
+ { priority: string; description: string }
+ >(CREATE_TODO_MUTATION)
+ );
+
+ render(, {
+ wrapper: ({ children }) => (
+ {children}
+ ),
+ });
+
+ let createTodo: Awaited>[0];
+ let reset: Awaited<
+ ReturnType
+ >[1]["reset"];
+
+ {
+ const [mutate, result] = await ProfiledHook.takeSnapshot();
+ createTodo = mutate;
+ reset = result.reset;
+ //initial value
+ expect(result.data).toBe(undefined);
+ expect(result.loading).toBe(false);
+ expect(result.called).toBe(false);
+ }
+
+ let fetchResult: any;
+ act(() => {
+ fetchResult = createTodo({
+ variables: { priority: "Low", description: "Get milk." },
+ });
+ });
+
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ // started loading
+ expect(result.data).toBe(undefined);
+ expect(result.loading).toBe(true);
+ expect(result.called).toBe(true);
+ }
+
+ act(() => reset());
+
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ // reset to initial value
+ expect(result.data).toBe(undefined);
+ expect(result.loading).toBe(false);
+ expect(result.called).toBe(false);
+ }
+
+ expect(await fetchResult).toEqual({ data: CREATE_TODO_DATA });
+
+ await expect(ProfiledHook).not.toRerender();
+ });
});
describe("Callbacks", () => {
diff --git a/src/react/hooks/useMutation.ts b/src/react/hooks/useMutation.ts
index f3c2b233abd..2eff46ee272 100644
--- a/src/react/hooks/useMutation.ts
+++ b/src/react/hooks/useMutation.ts
@@ -164,7 +164,9 @@ export function useMutation<
const reset = React.useCallback(() => {
if (ref.current.isMounted) {
- setResult({ called: false, loading: false, client });
+ const result = { called: false, loading: false, client };
+ Object.assign(ref.current, { mutationId: 0, result });
+ setResult(result);
}
}, []);