Skip to content

Commit

Permalink
Ensure last results are reset when working with partial data
Browse files Browse the repository at this point in the history
Issue #6334 exposed a problem where the `lastResult` mechanism
we use to prevent duplicate subscription notifications (when
data hasn't changed) can unintentionally block certain results
from propagating through Apollo Client. This leads to issues
like loading states not being updated properly, due to new
partial results looking similar to last results.

This commit ensures that last results are properly cleared out
when new partial results come in.

Fixes #6334.
  • Loading branch information
hwillson committed Jun 9, 2020
1 parent 594c8ae commit 4f3aa4d
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
{
"name": "apollo-client",
"path": "./dist/apollo-client.cjs.min.js",
"maxSize": "24.1 kB"
"maxSize": "24.2 kB"
}
],
"peerDependencies": {
Expand Down
4 changes: 3 additions & 1 deletion src/core/ObservableQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ export class ObservableQuery<
}
}

if (!partial) {
if (partial) {
this.resetLastResults();
} else {
this.updateLastResult(result);
}

Expand Down
91 changes: 91 additions & 0 deletions src/react/hooks/__tests__/useQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,97 @@ describe('useQuery Hook', () => {
console.error = consoleError;
}).then(resolve, reject);
});

itAsync('should update with proper loading state when variables change for cached queries', (resolve, reject) => {
const peopleQuery = gql`
query AllPeople($search: String!) {
people(search: $search) {
id
name
}
}
`;

const peopleData = {
people: [
{ id: 1, name: "John Smith" },
{ id: 2, name: "Sara Smith" },
{ id: 3, name: "Budd Deey" }
]
};

const mocks = [
{
request: { query: peopleQuery, variables: { search: '' } },
result: { data: peopleData },
},
{
request: { query: peopleQuery, variables: { search: 'z' } },
result: { data: { people: [] } },
},
{
request: { query: peopleQuery, variables: { search: 'zz' } },
result: { data: { people: [] } },
},
];

let renderCount = 0;
const Component = () => {
const [search, setSearch] = useState('');
const { loading, data } = useQuery(peopleQuery, {
variables: {
search: search
}
});
switch (++renderCount) {
case 1:
expect(loading).toBeTruthy();
break;
case 2:
expect(loading).toBeFalsy();
expect(data).toEqual(peopleData);
setTimeout(() => setSearch('z'));
break;
case 3:
expect(loading).toBeTruthy();
break;
case 4:
expect(loading).toBeFalsy();
expect(data).toEqual({ people: [] });
setTimeout(() => setSearch(''));
break;
case 5:
expect(loading).toBeFalsy();
expect(data).toEqual(peopleData);
setTimeout(() => setSearch('z'));
break;
case 6:
expect(loading).toBeFalsy();
expect(data).toEqual({ people: [] });
setTimeout(() => setSearch('zz'));
break;
case 7:
expect(loading).toBeTruthy();
break;
case 8:
expect(loading).toBeFalsy();
expect(data).toEqual({ people: [] });
break;
default:
}
return null;
}

render(
<MockedProvider mocks={mocks}>
<Component />
</MockedProvider>
);

return wait(() => {
expect(renderCount).toBe(8);
}).then(resolve, reject);
});
});

describe('Polling', () => {
Expand Down

0 comments on commit 4f3aa4d

Please sign in to comment.