Hello,
I’m updating apollo-client in my project from 3.3.21 to 3.4.16 but I’m struggling with the pagination.
The logic me and my colleagues implemented in the 3.3.x version is not working anymore because the readField utility is returning undefined when the query run the first time and the results are not cached yet.
We have defined the merge and read function in the cache typePolicies to be able to save a complex state where the cached data are divided between items received from the server (we call them ordered, because they respect a specific order), and data modified from the client, but not received yet from the server (we call them unOrdered, because their order is not precise, since it’s assumed by the client itself). These two sub-list are stored in an object, returned from the merge function and then merged together in the read function.
The code is the one below:
const cache = new InMemoryCache({
typePolicies: {
Folder: {
fields: {
children: {
keyArgs: ['sort'],
merge(
existing: NodesListCachedObject | undefined,
incoming: Reference[],
fieldFunctions: FieldFunctionOptions
): NodesListCachedObject {
const merged = mergeNodesList(existing, incoming, fieldFunctions);
// here we have some logic to retrieve the cursor, which is the id of the last merged.ordered element
// we use a readField<string>('id', lastOrderedElement) here that is returning undefined as well
return merged;
},
// Return all items stored so far, to avoid ambiguities
// about the order of the items.
read(existing: NodesListCachedObject | undefined): Reference[] | undefined {
if (existing) {
return readNodesList(existing);
}
return existing;
}
},
}
}
}
});
The actual function in charge of merging nodes is:
function mergeNodesList(
existing: NodesListCachedObject | undefined,
incoming: Reference[],
{ readField, mergeObjects }: FieldFunctionOptions
): NodesListCachedObject {
if (!existing) {
return {
ordered: incoming,
unOrdered: []
};
}
if (!incoming) {
return existing;
}
const newOrdered = keyBy(existing?.ordered, (item) => readField<string>('id', item));
const newUnOrdered = keyBy(existing?.unOrdered, (item) => readField<string>('id', item));
// add all incoming items
incoming.forEach((item: Reference) => {
const id = readField<string>('id', item);
let mergedNode = item;
if (id in newOrdered) {
mergedNode = mergeObjects(newOrdered[id], item);
}
newOrdered[id] = mergedNode;
// unOrderItem that now is ordered
if (id in newUnOrdered) {
delete newUnOrdered[id];
}
});
// finally, return an array again so that manual updates of the cache can work on the order of elements
return {
ordered: Object.values(newOrdered),
unOrdered: Object.values(newUnOrdered)
};
}
and the read function
function readNodesList(existing: NodesListCachedObject): Reference[] {
const ordered = existing.ordered || [];
const unOrdered = existing.unOrdered || [];
return [...ordered, ...unOrdered];
}
I’ve seen that some changes has been made in the cache logic in the 3.4 release, I’ve tried to investigate what is wrong and how to adapt to the new version but I’m giving myself a big headache.
Any idea of what is wrong with our code and how to update it?