Apollo-client: [2.0] Use cache breaks react-apollo

Created on 6 Oct 2017  路  27Comments  路  Source: apollographql/apollo-client

It's related to https://github.com/apollographql/react-apollo/issues/1192
But I think it's caused by apollo-client.

Intended outcome:
Scenario:
query1 + variables1 => data1
query1 + variables2 => data2
query1 + variables1 => data1

Actual outcome:
Same scenario:
query1 + variables1 => data1
query1 + variables2 => data2
query1 + variables1 => data2 instead of data1

How to reproduce the issue:
It breaks since [email protected] and it worked well with beta.2

I try to revert apollo-cache-inmemory, apollo-link, apollo-link-http with no impact so it's clearly cause by apollo-client

馃悶 bug

Most helpful comment

Reproduction created 馃帀 I'm on it!

All 27 comments

@hlehmann do you have a small reproduction for this? I'd love to take a look! Also, what version of react-apollo are you using?

@jbaxleyiii I believe https://github.com/apollographql/react-apollo/issues/1192, the discussion and explanation here https://github.com/apollographql/apollo-client/pull/2200#issuecomment-332338791, and https://github.com/apollographql/apollo-client/issues/2196 are all the same issue.

With the recycling behavior of ObservableQuery, in combination with a cache-only (no fetch) strategy, the ObservableQuery is not taking into account the variables passed to a query and returns the wrong data.

So, in the right circumstance, where the ObservableQuery is not torn down:

  1. Load query fuu with variable page: 1
  2. Load query fuu with variable page: 2
  3. Load query fuu with variable page: 1 - will return the wrong cached data for page: 2

We are seeing this on the latest betas of 2.0 in a user interface that is nearly identical to what I describe above or also in this description.

"apollo-cache-inmemory": "^0.2.0-beta.4",
"apollo-client": "^2.0.0-beta.4",
"apollo-link": "^0.7.0",

We're working around this by using fetchPolicy: 'network-only' at the moment, which will force a refetch, but isn't ideal and is just a temporary fix. This is currently one of the more significant blockers for us to migrate to 2.0. From my understanding, the solution proposed in https://github.com/apollographql/apollo-client/pull/2200 would fix the problem, or the implementation of a prepareForReuse API in conjunction with an update to react-apollo would also fix it.

@aortbals thanks for the detailed response! I will get a solution out for you ASAP and would love if you could try it out!

Awesome, thanks @jbaxleyiii. Looking forward to trying something out. Ping me if I can help!

@aortbals btw, what version of react-apollo are you using? This should have been fixed with the initial react-apollo 2.0 beta and was verified by @jamesreggio to be fixed with that release. Are you seeing the issue with that build?

@jbaxleyiii it is not fixed in react-apollo 2.0. I reported same issue https://github.com/apollographql/react-apollo/issues/1192 8 days ago.
I was using

"apollo-cache-inmemory": "^0.2.0-beta.3",
"apollo-client": "^2.0.0-beta.3",
"apollo-fetch": "^0.6.0",
"apollo-link-batch-http": "^0.2.1-beta.6",
"apollo-link-http": "^0.6.1-beta.6",
"react-apollo": "^2.0.0-beta.0",`

@jbaxleyiii I'm using react-apollo 2.0.0-beta.0. Personally, I've only seen this issue on the 2.x/beta series of releases.

@seeden would you be able to help me with a small reproduction using the reproduction template? I included a new test in the 2.0 of react-apollo specifically for this last week but it looks like I'm missing how its being run in your (and others) app to fix the bug

@aortbals @seeden a few more questions:

  • does this only happen when the watched component is unmounted then remounted (i.e page navigation)?
  • does this happen when calling refetch manually?

@jbaxleyiii no my component is mounted (I checked it). graphql decorator just get a new variable. ( I am switching between users profiles = I am not the same route)

@graphql(PROFILE_CONTAINER_QUERY, {
  options: ({ match: { params: { username } } }) => ({
    variables: {
      username,
    },
  }),
})

I may have been able to create a reproduction. Still investigating. This is my top priority today so expect a fix soon!

Reproduction created 馃帀 I'm on it!

Live action play by play:

  1. Original working code with some of the 2.0 betas
  2. Now broken version of the app with the latest
  3. Failing test written in react-apollo
  4. Failing test written in apollo-client

Thanks everyone for the issue report and help! I've fixed the bug here, verified it in react-apollo and in a sample app. Working on a new release now.

Heads up that we are in the RC mode so you will need to switch from @beta for apollo-client and apollo-cache-inmemory to @next.

React Apollo 2.0 is still in beta but should be in RC soon!

It works well for me. Thx !

@jbaxleyiii it looks like a query like this is fixed:

query UserQuery($id: ID) {
    user(id: $id) {
        id
        name
    }
}

However, when you use the variable nested, not at the root, it doesn't select the correct set of cached posts out of the cache (I can see that multiple sets of posts are cached like posts({"page":1}), posts({"page":2}) inside of a given user, but I'm seeing the same behavior as before with the wrong inner list being returned to the component.

query UsersQuery($page: Int) {
    users {
        id
        name
        posts(page: $page) {
            ...PostFragment
        }
    }
}

Let me know if this is making sense. Thanks!

@jbaxleyiii can you reopen this issue ?

@seeden can you try the newest rc (rc.4?)

I tried latest 2.0.0 it is not working. :(

I'm using apollo-client without react and I have the same issue so it's not related with the react package.
I'm using :
apollo-client 2.0.2
apollo-cache 1.0.0
apollo-cache-inmemory 1.1.0

The problem in my case is only with the cache. It seems the query observable doesn't use new options to get data from the cache but only options/variables passed at construct time.
If you use "cache-network" strategy, data from the cache are not as expected, but data from network are using the right variables.
As expected, if instead of using setOptions() on the observable I recall watchQuery() to get a new Observable, no problem.

Anthony

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions to Apollo Client!

Hi, I'm using that dependencies:

 "apollo-cache-inmemory": "^1.1.3",
 "apollo-client": "^2.1.0"

I had a similar problem with cache and variables but what is surprising change addTypename to false fixes the problem:

export const apolloClient = new ApolloClient({
  link: new HttpLink({ uri: '/graphql', fetch: fetch }),
  cache: new InMemoryCache({
    addTypename: false
  })
})

This should be fixed in recent versions of apollo-client. It not, definitely let us know. Thanks!

@hwillson in 2.4.2 the workaround above (thanks @coun7zero ) was still needed in one case - some data in object array was missing after some consecutive similar requests.

The query looks like this:

query ($minLat: Float!, $maxLat: Float!, $minLng: Float!, $maxLng: Float!, $clusterType: String!, $areas: [String]!, $isics: [String]!, $multiplier: Float!) {
  businesses {
    aggregationByAreaAndIsic(locationBoundingBox: {minimalLatitude: $minLat, maximalLatitude: $maxLat, minimalLongitude: $minLng, maximalLongitude: $maxLng}, areaAggregation: {areaClusterTypes: [$clusterType], highlightedAreas: $areas}, isics: $isics) {
      areaBuckets {
        area {
          id
          location {
            latitude
            longitude
          }
        }
        isicBuckets {
          size
          isic {
            id
            root {
              id
            }
          }
        }
        size
      }
    }
    aggregationByGeohashGridAndIsic(areas: $areas, locationBoundingBox: {minimalLatitude: $minLat, maximalLatitude: $maxLat, minimalLongitude: $minLng, maximalLongitude: $maxLng}, isics: $isics, precisionDistanceMultiplier: $multiplier) {
      geohashGridBuckets {
        id: geohash
        location {
          latitude
          longitude
        }
        isicBuckets {
          isic {
            id
            root {
              id
            }
          }
          size
        }
        size
      }
    }
    size(areas: $areas, isics: $isics)
  }
}

isicBuckets missed data (one object) after e.g. sending 2, then 3 (one additional) $isics, in a 3 -> 2 -> 3 change scenario with the same additional string. While changing bounding box back and forth it seemed way more random - sometimes old data stayed, sometimes it was even returned twice.

Was this page helpful?
0 / 5 - 0 ratings