apollographql / apollographql/apollo-client

`fetchMore` race conditions when paginating after change to `useQuery` variables

Open
#11,630 5 comments 5 reactions 0 assignees View on GitHub
:rose: has-reproduction 💸 caching
Dominant language
TypeScript
Stars
19.8k
Forks
2.9k
Avg merge
10h 17m
Merged PRs (30d)
19

Description

### Issue Description

I have a strange issue where two successive calls to `fetchMore` will cause a bug _only if the query was changed once before_.

### Reproduction outline
- `fetchpolicy = "network-only"`
- paginating with a:
- [x] custom merge function
- [ ] custom read function
- query can be updated to include one extra field of the same object
- make three requests of 10 items each as soon as:
1. page loads (✅ no problem)
2. query updates (🐞 bug)

### Link to Reproduction

[Code sandbox](https://codesandbox.io/p/sandbox/graphql-apollo-pagination-public-lhrh24?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clt5km8tt0006356h8jjgzsgr%2522%252C%2522sizes%2522%253A%255B70%252C30%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clt5km8tt0002356h4wmdflfa%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clt5km8tt0003356h55fwi6ch%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clt5km8tt0005356hmhz2a2ll%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B40.03706750894524%252C59.96293249105476%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clt5km8tt0002356h4wmdflfa%2522%253A%257B%2522id%2522%253A%2522clt5km8tt0002356h4wmdflfa%2522%252C%2522tabs%2522%253A%255B%255D%257D%252C%2522clt5km8tt0005356hmhz2a2ll%2522%253A%257B%2522id%2522%253A%2522clt5km8tt0005356hmhz2a2ll%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clt5km8tt0004356hdzuoj8uc%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522UNASSIGNED_PORT%2522%252C%2522port%2522%253A0%252C%2522path%2522%253A%2522%252F%2522%257D%255D%252C%2522activeTabId%2522%253A%2522clt5km8tt0004356hdzuoj8uc%2522%257D%252C%2522clt5km8tt0003356h55fwi6ch%2522%253A%257B%2522tabs%2522%253A%255B%255D%252C%2522id%2522%253A%2522clt5km8tt0003356h55fwi6ch%2522%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D)

### Reproduction Steps
1. Press the "change query" button
**Result:** `data` returned from `useQuery` is stale, despite sequential calls to `fetchMore` (`fetchMore` updates not present).

### Example workarounds:
- Reduce the number of times `fetchMore` is called, (instead of two times just one time: change line 46 - change number `30` to `20`)
- In the merge function, if the query is changed (detect by: **`incoming` is first ten items**), then throw away the merged result and return only `incoming`
- In the original query, call more than one field. In the updated query, call fewer of those fields (seems to return cached result despite using `"network-only"`)

### `@apollo/client` version

3.9.5

Contributor guide

Open the contributing guide

Research direction

Start with the linked CodeSandbox and reproduce the stale data after pressing “change query,” focusing on useQuery variables, fetchMore, and the custom merge function. Trace the pagination and cache behavior in the TypeScript client, then verify that successive fetchMore results remain current after the query changes.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, typescript
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.