convoyinc / apollo-cache-hermes

A cache implementation for Apollo Client, tuned for performance
Other
483 stars 30 forks source link

Cannot execute consecutive queries that would return the same data #405

Open nfantone opened 5 years ago

nfantone commented 5 years ago

This is a follow up to https://github.com/apollographql/react-apollo/issues/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:

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.

danieldunderfelt commented 5 years ago

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.

nfantone commented 5 years ago

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

wmertens commented 5 years ago

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

dios-david commented 5 years ago

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.