From e5acf910e39752b453540b6751046d1c19b66350 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Fri, 10 Nov 2023 11:29:38 +0100 Subject: [PATCH] `useMutation` also reset internal state on reset (#10931) --- .changeset/yellow-fans-move.md | 5 ++ .size-limit.cjs | 2 +- .../hooks/__tests__/useMutation.test.tsx | 87 ++++++++++++++++++- src/react/hooks/useMutation.ts | 4 +- 4 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 .changeset/yellow-fans-move.md 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); } }, []);