Skip to content

Commit cb8ffe5

Browse files
authored
Fix issue with useFragment where it returned wrong data when changing the from option (#11689)
1 parent 2b0820c commit cb8ffe5

File tree

4 files changed

+68
-2
lines changed

4 files changed

+68
-2
lines changed

.changeset/flat-singers-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@apollo/client": patch
3+
---
4+
5+
Fix issue where passing a new `from` option to `useFragment` would first render with the previous value before rerendering with the correct value.

.size-limits.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"dist/apollo-client.min.cjs": 39248,
2+
"dist/apollo-client.min.cjs": 39267,
33
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32630
44
}

src/react/hooks/__tests__/useFragment.test.tsx

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { concatPagination } from "../../../utilities";
2929
import assert from "assert";
3030
import { expectTypeOf } from "expect-type";
3131
import { SubscriptionObserver } from "zen-observable-ts";
32-
import { profile, spyOnConsole } from "../../../testing/internal";
32+
import { profile, profileHook, spyOnConsole } from "../../../testing/internal";
3333

3434
describe("useFragment", () => {
3535
it("is importable and callable", () => {
@@ -1359,6 +1359,61 @@ describe("useFragment", () => {
13591359
});
13601360
});
13611361

1362+
it("returns correct data when options change", async () => {
1363+
const client = new ApolloClient({
1364+
cache: new InMemoryCache(),
1365+
});
1366+
type User = { __typename: "User"; id: number; name: string };
1367+
const fragment: TypedDocumentNode<User> = gql`
1368+
fragment UserFragment on User {
1369+
id
1370+
name
1371+
}
1372+
`;
1373+
1374+
client.writeFragment({
1375+
fragment,
1376+
data: { __typename: "User", id: 1, name: "Alice" },
1377+
});
1378+
1379+
client.writeFragment({
1380+
fragment,
1381+
data: { __typename: "User", id: 2, name: "Charlie" },
1382+
});
1383+
1384+
const ProfiledHook = profileHook(({ id }: { id: number }) =>
1385+
useFragment({ fragment, from: { __typename: "User", id } })
1386+
);
1387+
1388+
const { rerender } = render(<ProfiledHook id={1} />, {
1389+
wrapper: ({ children }) => (
1390+
<ApolloProvider client={client}>{children}</ApolloProvider>
1391+
),
1392+
});
1393+
1394+
{
1395+
const snapshot = await ProfiledHook.takeSnapshot();
1396+
1397+
expect(snapshot).toEqual({
1398+
complete: true,
1399+
data: { __typename: "User", id: 1, name: "Alice" },
1400+
});
1401+
}
1402+
1403+
rerender(<ProfiledHook id={2} />);
1404+
1405+
{
1406+
const snapshot = await ProfiledHook.takeSnapshot();
1407+
1408+
expect(snapshot).toEqual({
1409+
complete: true,
1410+
data: { __typename: "User", id: 2, name: "Charlie" },
1411+
});
1412+
}
1413+
1414+
await expect(ProfiledHook).not.toRerender();
1415+
});
1416+
13621417
describe("tests with incomplete data", () => {
13631418
let cache: InMemoryCache, wrapper: React.FunctionComponent;
13641419
const ItemFragment = gql`

src/react/hooks/useFragment.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ function _useFragment<TData = any, TVars = OperationVariables>(
8888
diffToResult(cache.diff<TData>(diffOptions))
8989
);
9090

91+
// Since .next is async, we need to make sure that we
92+
// get the correct diff on the next render given new diffOptions
93+
React.useMemo(() => {
94+
resultRef.current = diffToResult(cache.diff<TData>(diffOptions));
95+
}, [diffOptions, cache]);
96+
9197
// Used for both getSnapshot and getServerSnapshot
9298
const getSnapshot = React.useCallback(() => resultRef.current, []);
9399

0 commit comments

Comments
 (0)