From 8f564f65c8607bda9c2c28465fec2afcd240279c Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 15 Mar 2024 16:59:43 -0600 Subject: [PATCH 1/4] Add failing test for rerender on options change --- .../hooks/__tests__/useFragment.test.tsx | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/react/hooks/__tests__/useFragment.test.tsx b/src/react/hooks/__tests__/useFragment.test.tsx index 27f4857edd6..d5436bc5097 100644 --- a/src/react/hooks/__tests__/useFragment.test.tsx +++ b/src/react/hooks/__tests__/useFragment.test.tsx @@ -29,7 +29,7 @@ import { concatPagination } from "../../../utilities"; import assert from "assert"; import { expectTypeOf } from "expect-type"; import { SubscriptionObserver } from "zen-observable-ts"; -import { profile, spyOnConsole } from "../../../testing/internal"; +import { profile, profileHook, spyOnConsole } from "../../../testing/internal"; describe("useFragment", () => { it("is importable and callable", () => { @@ -1359,6 +1359,61 @@ describe("useFragment", () => { }); }); + it("returns correct data when options change", async () => { + const client = new ApolloClient({ + cache: new InMemoryCache(), + }); + type User = { __typename: "User"; id: number; name: string }; + const fragment: TypedDocumentNode = gql` + fragment UserFragment on User { + id + name + } + `; + + client.writeFragment({ + fragment, + data: { __typename: "User", id: 1, name: "Alice" }, + }); + + client.writeFragment({ + fragment, + data: { __typename: "User", id: 2, name: "Charlie" }, + }); + + const ProfiledHook = profileHook(({ id }: { id: number }) => + useFragment({ fragment, from: { __typename: "User", id } }) + ); + + const { rerender } = render(, { + wrapper: ({ children }) => ( + {children} + ), + }); + + { + const snapshot = await ProfiledHook.takeSnapshot(); + + expect(snapshot).toEqual({ + complete: true, + data: { __typename: "User", id: 1, name: "Alice" }, + }); + } + + rerender(); + + { + const snapshot = await ProfiledHook.takeSnapshot(); + + expect(snapshot).toEqual({ + complete: true, + data: { __typename: "User", id: 2, name: "Charlie" }, + }); + } + + await expect(ProfiledHook).not.toRerender(); + }); + describe("tests with incomplete data", () => { let cache: InMemoryCache, wrapper: React.FunctionComponent; const ItemFragment = gql` From f31dbd88569ebe62fa29887f185b735ae0f68212 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 15 Mar 2024 17:01:56 -0600 Subject: [PATCH 2/4] Add fix for fragment rerendering with incorrect data --- src/react/hooks/useFragment.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/react/hooks/useFragment.ts b/src/react/hooks/useFragment.ts index 96e2a1c014a..660beca220f 100644 --- a/src/react/hooks/useFragment.ts +++ b/src/react/hooks/useFragment.ts @@ -88,6 +88,12 @@ function _useFragment( diffToResult(cache.diff(diffOptions)) ); + // Since .next is async, we need to make sure that we + // get the correct diff on the next render given new diffOptions + React.useMemo(() => { + resultRef.current = diffToResult(cache.diff(diffOptions)); + }, [diffOptions, cache]); + // Used for both getSnapshot and getServerSnapshot const getSnapshot = React.useCallback(() => resultRef.current, []); From f0fe165b5a1efb4a7b82634734176b2d692eb3cf Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 15 Mar 2024 17:04:50 -0600 Subject: [PATCH 3/4] Add changeset --- .changeset/flat-singers-kiss.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/flat-singers-kiss.md diff --git a/.changeset/flat-singers-kiss.md b/.changeset/flat-singers-kiss.md new file mode 100644 index 00000000000..74727e85370 --- /dev/null +++ b/.changeset/flat-singers-kiss.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Fix issue where passing a new `from` option to `useFragment` would first render with the previous value before rerendering with the correct value. From 48e213f38747a0ac960bb8648a37f450ab5aef6c Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 15 Mar 2024 17:10:55 -0600 Subject: [PATCH 4/4] Update size limits --- .size-limits.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.size-limits.json b/.size-limits.json index cdae2c9cd42..6ea6a4c6ebc 100644 --- a/.size-limits.json +++ b/.size-limits.json @@ -1,4 +1,4 @@ { - "dist/apollo-client.min.cjs": 39247, + "dist/apollo-client.min.cjs": 39267, "import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32630 }