convoyinc / apollo-cache-hermes

A cache implementation for Apollo Client, tuned for performance

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot execute consecutive queries that would return the same data

nfantone opened this issue · comments

This is a follow up to apollographql/react-apollo#1931

Summary:
If executing the same query two (or more) consecutive times that would return the same data, observers listening to events from apollo-client client.watchQuery are not notified of the change. This leads to necessary UI updates not occurring. In particular, <Query> component from react-apollo does not re-render and stays in "loading" state.

Here is a repro case:

Edit apollo-client-error-template

  1. Click on "Run query".
  2. Query is executed, people list is updated.
  3. Click on "Run query" again to trigger a second query that would fetch the same data.
  4. Notice how UI gets stuck in "Loading...".

Now, go to index.js, switch cache to apollo-cache-inmemory and try above again. It'll work just fine.

Expected Behavior:

  • Observers, such as react-apollo's Query component, are always notified of the the query's network result, regardless of its content.
  • apollo-cache-inmemory functionality is matched.

Actual Behavior:

Two (or more) consecutive queries that would return the exact same data do not trigger re-renders of components expecting changes to the store.

I'm seeing the same issue. I initially thought it only happens when the server returns empty data, but good to know that it also happens for any data that is the same as last time. WIll switch to inmemory for now.

Sad that we are not hearing anything from owners. This is a deal-breaker for us on switching to apollo-cache-hermes.

I wonder what causes this. There must be some side-effect that apollo-client is counting on to update the loading state?

After taking a quick look into this issue, I found that the ObservableQuery implementation in apollo-client has a method called isDifferentFromLastResult which compares the previous and the new results when a query change happens. If the networkStatus + stale + data properties are equal in both results, the update won't be triggered.

When I change a query using apollo-cache-inmemory this method is being called twice:
initial state: loading: false, networkStatus: 7, data: <oldData>
(fetching data...)
1st call: loading: true, networkStatus: 2, data: <oldData>
(fetching data finished)
2nd call: loading: false, networkStatus: 7, data: <newData>

In my case the data is the same (oldData = newData), but this method will return true in both cases, because the loading and the networkStatus properties have different values.

When I change a query using apollo-cache-hermes this method is being called only once:
initial state: loading: false, networkStatus: 7, data: <oldData>
(fetching data...)
(fetching data finished)
1st call: loading: false, networkStatus: 7, data: <newData>

Because oldData=newData, and loading and networkStatus has the same values as the previous result, this method will return false so no update will be triggered.

Basically, the "loading state" result is missing when using apollo-cache-hermes, that's why this logic breaks in apollo-client. When I modified this method in apollo-client to return true always, this issue disappeared and worked as expected. I don't know which component is responsible for this, but I think the proper fix for this is to emit a result with a "loading state" to match the behaviour of apollo-cache-inmemory and satisfy this check in apollo-client.

I hope this info helps someone in fixing this issue.