-
Notifications
You must be signed in to change notification settings - Fork 91
Pagination #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pagination #44
Conversation
bmullan91
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like the right approach 👍I've suggested we move the update fn into the options, since we're already passing + extending them via useQuery and useClientRequest.
Should the fn be called update which would match Apollo's name for the same function, or updateResult?
ff7f88f to
6a020ca
Compare
bmullan91
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
src/useQuery.js
Outdated
| fetchMore: ({ variables, ...rest } = {}) => | ||
| // merge variables so they don't all have to be passed back in, | ||
| // just the ones that are changing | ||
| queryReq({ ...rest, variables: { ...allOpts.variables, ...variables } }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😍
|
|
||
| expect(fetchData({ variables: { limit: 20 } })).rejects.toThrow( | ||
| 'options.updateResult must be a function' | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏 excellent tests
refetch can be used to achieve the same
|
@bmullan91 as discussed earlier I've removed I've also added a pagination guide to the README that includes distinct page & infinite loading examples. If you could take another look when you get a chance please, hopefully we can get this in next week 😀 |
src/useClientRequest.js
Outdated
| if (typeof revisedOpts.updateResult !== 'function') { | ||
| throw new Error('options.updateResult must be a function'); | ||
| } | ||
| result.data = revisedOpts.updateResult(state.data, result.data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the name is updateResult, maybe we should pass the entire result? It might be useful for a developer to change / override the errors in some circumstances.
useClientRequest would then look something like:
let result = await client.request(revisedOperation, revisedOpts);
if (revisedOpts.updateResult) {
if (typeof revisedOpts.updateResult !== 'function') {
throw new Error('options.updateResult must be a function');
}
result = revisedOpts.updateResult(state, result)
}The pagination example updateResult:
const updateResult = (prevResult, newResult) => ({
...newResult,
data: {
...newResult.data,
allPosts: [...prevResult.data.allPosts, ...result.data.allPosts]
}
});
useQuery(MY_QUERY, {
updateResult
})It makes updating the data a bit more verbose, but the developer could write a wrapper if it was a really common usecase:
const dataUpdater = (fn) => (prevResult, newResult) => ({
...newResult,
data: fn(prevResult.data, newResult.data)
})There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, passing the entire result back allows internal properties like loading & error to be changed, or new ones to be added which could be abused or cause tricky bugs. We're going to rename this to updateData as a better description of what it's doing & if we see a use case for changing / overriding errors in the future, we could always introduce an updateErrors option.
bmullan91
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍 - some minor comments just
| count | ||
| } | ||
| } | ||
| `; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should simplify the example - this is could be:
ALL_POSTS_QUERY = `
query($limit: Int, $skip: Int) {
allPosts(limit: $limit, skip: $skip) {
total,
items {
id
title
}
}
}
`There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the separation between data & meta is good here? There are redundant parts to this example that could be removed & make it more readable though, how about:
export const ALL_POSTS_QUERY = `
query allPosts($first: Int!, $skip: Int!) {
allPosts(first: $first, skip: $skip) {
id
title
url
}
_allPostsMeta {
count
}
}
`;| refetch: (options = {}) => | ||
| queryReq({ | ||
| skipCache: true, | ||
| updateData: (_, data) => data, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: We should add a comment here saying why we're doing this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, I've added an explanation & added a note to the README for refetch
bmullan91
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work @jackdclark 🙌
Closes: #41, closes #42, and closes #29
Provides aRemoved this as the same can be achieved withfetchMorefunction that will send the same query with the provided options merged into the original options, meaning the consumer doesn't have to manually maintain the state.refetchnow that it acceptsoptions.useQueryaccepts anupdateDatafunction as part of theoptionsobject that enables control of how the previous & new results are merged, this function can be overridden if necessary when callingrefetchas well.TODO
Example usage