apollo
apollo copied to clipboard
v4: Refetch does not use typePolicies as documented in Apollo 3 docs
Describe the bug
Apollo 3 recommends using InMemoryCache typePolicies for cache operations for pagination instead of updateQuery on the fetchMore function.
When trying to use typePolicies with vue-apollo, the behaviour is not as intended.
To Reproduce Steps to reproduce the behavior:
- Create Apollo Client using an InMemoryCache which has some typePolicies for the paginated query (define merge and read functions)
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
paginatedField: {
keyArgs: ['filter'],
merge (existing = makeEmptyPaginatedData(), incoming, { args: { page = 0, count = 10 } }) {
console.log('merge options:', page, count, 'data:', incoming);
const start = page * count;
const merged = existing.items.slice(0);
for (let i = 0; i < incoming.items.length; ++i) {
merged[start + i] = incoming.items[i];
}
return Object.assign({}, incoming, {
items: merged,
index: existing.index !== -1 && existing.index < incoming.index ? existing.index : incoming.index,
count: merged.length,
hasPrevious: start > 0 ? existing.hasPrevious : incoming.hasPrevious,
hasNext: start + count < merged.count ? existing.hasNext : incoming.hasNext,
});
},
read (existing, { args: { page = 0, count = 10 } }) {
if (!existing) {
return;
}
const start = page * count;
const end = start + count;
const items = existing.items.slice(start, end);
const result = Object.assign({}, existing, {
items,
index: page,
count: items.length,
hasPrevious: page > 0,
hasNext: existing.items.length > end || existing.hasNext,
});
console.log('read options:', page, count, 'data:', result);
return result;
},
},
},
},
},
});
- Define paginated query
const { result, fetchMore } = useQuery(
gql`query ($page: Int, $count: Int) {
paginatedField(filter: [...], page: $page, count: $count) {
index
count
hasPrevious
hasNext
items {
[...]
}
}
}`,
{
page: 0,
count: 10,
},
);
- Load page (initial query ran with variables page=0, count=10)
- Call fetchMore with variables page=1, count=10
- Console output:
merge options: 0 10 data: [...]
read options: 0 10 data: [...]
// here fetchMore is called
merge options: 1 10 data: [...]
read options: 0 10 data: [...]
Expected behavior Read function should be called with variables from most recent query (e.g. fetchMore call) just like merge function is called Console would read as follows:
merge options: 0 10 data: [...]
read options: 0 10 data: [...]
// here fetchMore is called
merge options: 1 10 data: [...]
read options: 1 10 data: [...]
Versions vue: 2.6.12 vue-apollo: @vue/[email protected] apollo-client: 3.3.18
Additional context Add any other context about the problem here.
Research guided me towards this Apollo issue, however I could not figure out how to apply this to solve my problem. #1115 also seems to be similar, but didn't provide a clear solution either.
@lucatk Did you ever find a solution for this?
I found an undesirable workaround. If you wrap variables in a ref when passing to useQuery it seems to function correctly. I suspect because it is a ref, it is always taking the current value of variables.
const variables = ref({
page: {
limit: 20,
offset: (parseInt((route.value.query.page as string) || 0) - 1) * 20,
returnTotalCount: true,
},
})
const { result, loading, fetchMore } = useQuery(packageQuery, variables)
watch(page, (newPage) => {
variables.value.page.offset = (newPage - 1) * limit.value
fetchMore({
variables: variables.value,
})
})
Looks like an apollo client issue to me.
The react useQuery doesn't do anything special too