Oh gosh, I see the issue now. You said something that made the issue obvious and I should have noticed this earlier. So sorry long day!
When using fetchMore
, the fetchPolicy
is temporarily set to no-cache
to guarantee that a network request is made, regardless of the fetch policy set by the hook. If you’re just using variables on the hook, then the hook will abide by the fetchPolicy
when new variables are passed in. In your case you’re using the default fetchPolicy
which is cache-first
. This means that changing variables will try to read from the cache, and if it can fulfill the data, it will return data from the cache. Since you’re setting keyArgs
on that field to just section
, offset
and limit
aren’t a part of the cache key, so the cache thinks it can fulfill the data required for that query which means you won’t see a network request made. That is why you’re only getting those first 3 results, then changing variables on the hook does nothing (it is essentially just rereading that data from the cache for the same section
, so it pulls those 3 records from the cache).
What I’d recommend is also adding a read
function that returns undefined
when the array doesn’t contain enough data to fulfill the limit/offset. As you can see, the offsetLimitPagination
helper doesn’t include a read
function, just a merge
function, reason being that we don’t know whether you want to do page-based pagination or an infinite scroll type UX where you return all records fetched so far.
Try adding a read
function along these lines and this should help ensure the query is fetched properly just by passing new variables
to the hook without the need for fetchMore
:
fields: {
entries: {
// use the `keyArgs` and `merge` function returned from the helper
...offsetLimitPagination(["section"]),
read(entries, { args }) {
// Best to add defaults for args in case args aren't provided in your query.
// Choose ones that make sense in your app. These are examples.
const { offset = 0, limit = 10 } = args;
// Handle when `entries` is `undefined` in case this field hasn't been
// fetched yet
const records = entries?.slice(offset, offset + limit) ?? [];
if (records.length < limit) {
// Force a fetch with an early return if there aren't enough
// records in the array to fulfill the data required by `args`.
return;
}
return records;
}
}
}
Obviously tweak this logic to suit your needs, but this should demonstrate the sort of thing you’ll want to do. Again, the key is returning undefined
to force a fetch from the server to ensure that network request is actually made.
The only tricky thing here is trying to determine when you’ve reached the end of the list (assuming you want to stop the query from refetching the last page over and over, if thats a concern of yours). Since you’re just returning a simple array and no page information, you’ll probably want to store some additional meta information that detects when you’ve reached the end of the list. This will be useful in the read
function to ensure you don’t return undefined
when you’ve reached the end of the list.
I’d recommend using the storage
util passed to both the merge
and read
functions. This is a plain object that allows you to store your own meta information and is scoped only to this field. It would look something like this:
read(entries, { storage, args }) {
// ...
// default `hasMore` to true in case we haven't fetched anything yet
// (i.e. the `merge` function hasn't been run yet)
const { hasMore = true } = storage
// Make `hasMore` part of the condition that causes a fetch.
// `merge` will set this to `false` once it detects the end of the list
if (records.length < limit && hasMore) {
return
}
return records;
},
merge(existing, incoming, { args, storage }) {
// ...
// Replace with your own logic, but detecting if we fetched less than
// `limit` might be enough to detect the end of the list.
storage.hasMore = incoming.length === args.limit
// ...
}
Hopefully this gives you an idea of how to use storage
. Apologies that storage
utility isn’t documented very well, but it can definitely be super useful here!
Even if you don’t need storage
to keep track of the end of the list, definitely try at the very least implementing a read
function and that should do the trick. Let me know how it goes!