Watcher stores DiffResult instead of ApolloQueryResult into query's newData
See original GitHub issueI’ve been having this problem where the data is sometimes missing for a component during a react update.
After much debugging, I think I have found the cause. I’m not sure how to reproduce it quite yet, since I’m still learning the working of apollo-client.
I first realized something was wrong when looking in the debugger here:
const { newData } = this.getQuery(observableQuery.queryId);
if (newData) {
return maybeDeepFreeze({ data: newData.data, partial: false }); // <--- HERE
} else {
At this point I see that newData
has fields result
and complete
- it is a Cache.DiffResult
instance rather than ApolloQueryResult
.
How does this happen?
Well, I can trace it back to:
public updateQueryWatch(
queryId: string,
document: DocumentNode,
options: WatchQueryOptions,
) {
const { cancel } = this.getQuery(queryId);
if (cancel) cancel();
return this.dataStore.getCache().watch({
// ... snip snip ...
callback: (newData: ApolloQueryResult<any>) => {
this.setQuery(queryId, () => ({ invalidated: true, newData })); // <--- HERE
},
});
}
This is where I can see the offending value placed into the query. On this line, newData
is of the wrong type.
Looking at https://github.com/apollographql/apollo-client/blob/master/packages/apollo-cache-inmemory/src/inMemoryCache.ts#L244 I can see that it does in fact pass a Cache.DiffResult
to the watcher callback:
private broadcastWatches() {
// Skip this when silenced (like inside a transaction)
if (this.silenceBroadcast) return;
// right now, we invalidate all queries whenever anything changes
this.watches.forEach((c: Cache.WatchOptions) => {
const newData = this.diff({
query: c.query,
variables: c.variables,
// TODO: previousResult isn't in the types - this will only work
// with ObservableQuery which is in a different package
previousResult: (c as any).previousResult && c.previousResult(),
optimistic: c.optimistic,
});
c.callback(newData); // <--- HERE
});
}
Notice how newData is the result of diff
when passed to the callback.
I’m not sure exactly who the offender is here - that is, where exactly the DiffResult
was supposed to become an ApolloQueryResult
. Maybe here: https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/QueryManager.ts#L730 it should have constructed one from the DiffResult
?
The symptom I get from this is that the components reload in an endless loop, but I think it may be this bug is just causing some confusion and it thinks something needs to be loaded that is already loaded.
Issue Analytics
- State:
- Created 6 years ago
- Comments:5 (5 by maintainers)
@dobesv thank you for the detailed investigation! I’ll take a look and see if I can reproduce!
@dobesv this has been adjusted in the next release!