Intended outcome:
Calling fetchMore
on a paginated query concatenates results to existing query.
Actual outcome:
I see 2 requests in the network tab, one with the correct offset
value, another with the original value. Results of the fetchMore
query are not concatenated to the original list.
How to reproduce the issue:
I have a schema that looks like this:
input PostFindArgs {
...
order: String
offset: Int
}
type Post {
id: Int
text: String
...
}
type Query {
posts(params: PostFindArgs): [Post]
}
Cache configuration like this:
const client = new ApolloClient({
link: ApolloLink.from([authLink, errorLink, httpLink]),
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
posts: {
// keyArgs: ['params.order'],
merge(existing = [], incoming) {
return [...existing, ...incoming];
},
},
//concatPagination(['params']),
},
},
},
}),
And usage like this:
const { data, refetch, loading, fetchMore } = useQuery(POSTS_QUERY, {
variables: { params: { order: 'newest', offset: 0, ... } },
});
// button calls this
fetchMore({variables: {params: {offset: 10}}});
I didn't see anything in the documentation about how to handle keyArgs
if the query arguments are an object. I would like to do something like keyArgs: ['params.order']
, but that throws an error. I imagine the problem here is that without keyArgs
, the object containing {offset: 10}
resolves in the cache as a separate query, so it doesn't concatenate results to the existing query. I also tried using the concatPagination
helper, with no luck.
However, while this might explain the missing concatenated results, it doesn't explain why I see 2 fetches in the network tab. A console.log
shows that the fetchMore
function is only called once, but I still see 2 network requests, one with the correct offset, and a second with the original offset.
Does Apollo Client v3 support object-based keyArgs
? If not, should I go back to using updateQuery
?
Versions
System:
OS: macOS 10.15.7
Binaries:
Node: 14.15.0 - ~/.nvm/versions/node/v14.15.0/bin/node
Yarn: 1.13.0 - /usr/local/bin/yarn
npm: 6.14.8 - ~/.nvm/versions/node/v14.15.0/bin/npm
Browsers:
Chrome: 86.0.4240.198
Edge: 86.0.622.63
Firefox: 66.0.3
Safari: 14.0
npmPackages:
@apollo/client: ^3.2.5 => 3.2.5
apollo-upload-client: ^14.1.3 => 14.1.3
Hi, I already posted an issue with the "double query" #7307 (which happens to me only with fetchPolicy set with 'network-only' or 'cache-and-network').
However, I believe that "keyArgs" takes an array of the "variables" object keys. Since your call is structured like this variables: { order: 'newest', offset: 0, ... }
, keyArgs: ['order']
should suffice. Because it depends on the variables you always can "split" your args in your query.
A more detailed fetchMore example there : #7302
@jgan42 whoops, I had an error the way I typed out my example. Thanks for catching that.
variables: { params: { order: 'newest', offset: 0, ... } }
(Note, variables: { params: { ...} }
instead of variables: { ... }
.)
I found your issue earlier, but unfortunately the const [offset, setOffset] = useState(0)
, with fetchMore(...).then(() => setOffset(o => o + res.data.posts.length))
trick did not work for me. If I do that, I instead see the query fetched THREE times instead of two. First, with the correct offset, then with the original offset, then a third time with the correct offset again.
I suspect it has something to do with my query variables encapsulated in an object. I.E. The type is
{variables: {params: PostFindArgs} }
@CaptainStiggz We do support nested objects for both keyArgs
and keyFields
, though the syntax is a little unusual: keyArgs: ["params", ["order"]]
gives you a field key like posts({"params":{"order":...}})
, and keyArgs: ["params", ["order", "offset"]]
gives a field key like posts({"params":{"order":...,"offset":...}})
. The benefit of this array-based syntax is that it fully specifies the order of the keys, so you don't have to worry about non-deterministic JSON.stringify
serialization.
@benjamn , could we add that syntax for nested args to the docs? I spent an hour this morning trying to figure that out when I came across this issue. Would be super useful as a callout/example.
Just spent two hours to get how to do the nested argument stuff. Please, please add this to the documentation !
Most helpful comment
@CaptainStiggz We do support nested objects for both
keyArgs
andkeyFields
, though the syntax is a little unusual:keyArgs: ["params", ["order"]]
gives you a field key likeposts({"params":{"order":...}})
, andkeyArgs: ["params", ["order", "offset"]]
gives a field key likeposts({"params":{"order":...,"offset":...}})
. The benefit of this array-based syntax is that it fully specifies the order of the keys, so you don't have to worry about non-deterministicJSON.stringify
serialization.