Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fetchMore not using cache even with @client directive. ( fetchPolicy hardcoded to "no-cache" ) #8541

Open
ghost opened this issue Jul 26, 2021 · 4 comments

Comments

@ghost
Copy link

ghost commented Jul 26, 2021

Im trying to implement pagination over client side data. No network. I have implemented some typePolicies to use a local array as source of data. When executing the query, everything works as espected, but when i call fetchMore the data comes empty instead of the "next page"...

Having this:

const ALL_PEOPLE = gql`
  query GetPeople( $cursor:Int ) {
    getPeople( cursor:$cursor ) @client {
      cursor,
      listOfPeople {
        id
        name
      }
    }
  }
`;
  const {
    loading,
    data,
    fetchMore
  } = useQuery(ALL_PEOPLE); 

when calling this:

 fetchMore({  variables: { cursor: data.getPeople.cursor } }) //<-- this results in no new data added

Intended outcome
especting data.getPeople.listOfPeople to have the extra data added to it,...
Actual outcome
data.getPeople.listOfPeople remains unchanged, looks the same as the first value returned by useQuery hook.

How to reproduce the issue:
Created this error scenario using the error template: https://github.com/P48L0/react-apollo-error-template
Code of the error case is here: https://github.com/P48L0/react-apollo-error-template/blob/main/src/index.jsx

When you click "load more" the name 'Sara Smith' should be added to the list... but it is not added.

Discussed in https://github.com/apollographql/apollo-client/discussions/8540

Originally posted by P48L0 July 26, 2021
hi, im using "@apollo/client": "^3.3.21" and, while working on the client side, i was using "@client" on query calls as a way to "mock" server responses definging typePolicies on the InMemoryCache object. This works as espected when executing the queries from the useQuery hooks. But...

... the problem starts when trying to test pagination. When calling fetchMore, the response always comes in empty. Looking at the source code, i see that the combinedOptions used by that method sets fetchPolicy to "no-cache" and there's no way to change that... i was initially thinking that the code would see the @client and go straight to the cache, but no... it's still not clear to me what is happening but one thing im sure is that the cache is not being hit at all.

The question: is there a way to test pagination (using fetchMore) with purely local data? What if i want to fetch more on local data? there's no way?

@ghost ghost changed the title ObservableQuery.fetchMore & fetchPolicy: "no-cache" fetchMore not using cache even with @client directive. ( fetchPolicy fixed to "no-cache" ) Jul 26, 2021
@ghost ghost changed the title fetchMore not using cache even with @client directive. ( fetchPolicy fixed to "no-cache" ) fetchMore not using cache even with @client directive. ( fetchPolicy hardcoded to "no-cache" ) Jul 26, 2021
@benjamn benjamn self-assigned this Jul 26, 2021
@ghost
Copy link
Author

ghost commented Jul 28, 2021

I think i misinterpreted the goal of fetchMore. After more reading and testing i found the issue.

I initially thought that if you used the @client directive in the query then ApolloClient would call the read method of the pertinent field in typePolicies every time. So calling fetch more on a query with @client would call read again

But, i see now that read is only called one time per query ID. And fetchMore was aimed at fetching new data from the network because it would make no sense to fetch more form local since you already had that data delivered in the first call to useQuery...

fetchMore then means "fetch me more data for this query id" so it makes sense the result of useQuery is always the same in my error case. Because fetchMore returns an empty object (since in my case there's no network implementation) so no new data is appended to the original query result.

So there's no "issue"... BUT, it would be useful to make it work as i initially thought... if you flag a query field as @client we are indeed kinda saying that we want that field to be fetched locally... So fetchMore "should" call read on the typePolicies and use that result to update the query result...

@ladrone-vincet
Copy link

Hey there!
I think I may have run into a similar issue. I use field policy to specify some local-only GraphQL variables that are used in the query. Unfortunately when using fetchMore all of them seem to be undefined. I use complex keyArgs ["params", ['alertIds']]. I tried to experiment with fetchPolicy and nextFetchPolicy but without results. I am pretty new to Apollo, so sorry if I missed something obvious.

Query:

query GetMentions($alertIds: [Int], $sort: MentionsSort, $offset: Int, $limit: Int) {
  selectedAlertIds @client @export(as: "alertIds")
  mentionsSort @client @export(as: "sort")
  mentionStream(params: {alertIds: $alertIds, sort: $sort, offset: $offset, limit: $limit}) {
    lastUpdated
    total
    mentions {
      id
    }
  }
}

Hook:
I tried {fetchPolicy: 'cache-and-network', nextFetchPolicy: 'cache-first'} combination but it didn't help.

FieldPolicy:
Sample local-only field:

            Query: {
              fields: {
                selectedAlertIds() {
                  console.log("🚀 ~ file: apollo.ts ~ line 91 ~ selectedAlertIds ~ reactiveVariables.selectedNodes()", reactiveVariables.selectedNodes())
                  return reactiveVariables.selectedNodes()?.[0]?.alertIds ?? []
                },

FetchMore call:

fetchMore({variables: {offset: foo.length, limit: 10}})

some logs:

// initial call
args: Object { alertIds: [], sort: {…}, offset: undefined, limit: undefined } 
// random bug that shows up
args Object { alertIds: undefined, sort: undefined, offset: undefined, limit: undefined }
// fetchMore 
args Object { alertIds: undefined, sort: undefined, offset: 10, limit: 10 }

@ghost
Copy link
Author

ghost commented Aug 13, 2021

@ladrone-vincet what's the implementation of mentionsSort ? post the typePolicies. Hard to tell the problem based on your code...

One thing i can say in case it helps you... the "read" method of the TypePolicy of mentionsSort will be called only once. Not per query...

fetchMore will always fetch the network.
But the "read" method of a local resolver in TypePolicy will be called one time per keyArgs combination... remember the cache is caching the value in-memory. It makes no sense to call it over and over again since it is already cached.

In my case that was my misinterpretation that lead me to the error/weird behaviour.

@m-lautenbach
Copy link

But the "read" method of a local resolver in TypePolicy will be called one time per keyArgs combination

That's not true.
I'm currently "investigating" this and the behaviour is very strange.
As far as I can tell, read is called when:

  • any argument changes (not only keyArgs), but when encountering the same arguments multiple times, it does not anymore call read (?)
  • the query is done from a different hook (I think?)
    But not entirely sure.

It's definitely not as straight forward as keyArgs change, at least with custom merge and read functions.

I'm not using the @client directive, but I figured this comment might still be helpful input.

@apollo/client@3.7.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants