I try to implement cached pagination, in my react app using apollo client.
my query has filter argument, which should be the only argument that create a new key in the cache object.
for some reason, when fetchMore occurs with filter specified, the new data doesn't cause a re-render in the component.
I logged the existing and incoming argument in the merge function, and it seems that for each fetchMore that had filter, new data did arrive. so, i don't understand why the component didn't re-render.
to make things worst: calling fetchMore several times with or without filter send http request and merging the incoming data with the existing data. which i'd expect wouldn't happen as the client should see that it already has a key in the cache for that query with that key argument.
the following is the query:
query Shells($first: Int = 5, $offset: Int = 0, $filter: ShellFilter) {
shells(
orderBy: [STATUS_ASC, EXECUTION_FROM_DESC]
first: $first
offset: $offset
filter: $filter
) {
nodes {
...ShellData
}
totalCount
}
}
the apolloClient config is like this:
const client = new ApolloClient({
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
shells: {
keyArgs: ['filter'],
merge: (existing, incoming) => {
console.log('existing:', existing, 'incoming:', incoming);
return mergeObjectsAndNestedArrays<ShellsConnection>(
existing,
incoming,
'nodes',
);
},
},
},
},
},
})
and the component that displays it:
const ControlCenter = () => {
const { showModal } = useModalContext();
const [page, setPage] = useState(1);
const { data, loading, fetchMore } = useShellsQuery();
const [query, setQuery] = useURLQuery();
const onCounterpartiesChange = async (counterparties) => {
await fetchMore({
variables: {
filter: { shellCounterParties: { some: { orgId: { in: '20584' } } } },
},
});
setQuery({ counterparties });
};
const shells = data?.shells?.nodes;
console.log('hello from shells:', shells);
these are the logs:
EDIT 1 - docs reference
Following the docs: https://www.apollographql.com/docs/react/pagination/key-args/#setting-keyargs
any argument can be used as the keyArgs: limit
, offset
and filter
.
In the documentation examples, the arg used as the key is a primitive value, but in your case, the filter arg is an object. This could be causing apollo to see all results as the same cached version. If your data depend only on the orgID I think you could try the nested array notation to set that field as the key.
keyArgs: ["filter", ["shellCounterParties", ["some", ["orgId", ["in"]]]]]
or the custom function
keyArgs: (args, context) => args.filter.shellCounterParties.some.orgId.in
If you really need to cache according to the whole filter object, I guess the simplest way would be stringifying it
keyArgs: (args, context) => JSON.stringify(args.filter)
But to be sure how apollo is caching the data, I highly recommend you to try the apollo devtools
related: https://github.com/apollographql/apollo-client/issues/7314