Reputation: 133
I have a small learning project build with React, TS, & Apollo. As backend I am using https://graphqlzero.almansi.me/
The result I am looking for is:
Here is my container
export const GET_POSTS = gql`
query GetPosts($options: PageQueryOptions!) {
posts(options: $options) {
data {
id
title
body
}
}
}
`
const Posts = (): JSX.Element => {
const [page, setPage] = useState<number>(1)
const { data, fetchMore} = useQuery(GET_POSTS, {
variables: {
options: {
paginate: {
page: 1,
limit: 5,
},
},
},
nextFetchPolicy: "cache-first"
},
)
return (
<div>
<ListOfPosts {...{data,fetchMore,page,setPage }} />
</div>
)
}
and ListOfPosts
const ListOfPosts = ({ data,fetchMore, page, setPage }) => {
const getNextPage = (): void => {
fetchMore({
variables: {
options: {
paginate: {
page: page + 1,
limit: 5,
},
},
},
})
setPage((p: number) => p + 1)
}
const getPrevPage = (): void => {
setPage((p: number) => (p === 0 ? p : p - 1))
}
console.log(data)
return (
<div>
<p>current page{page}</p>
<button type="button" onClick={getPrevPage}>
Get Prev Page
</button>
<button type="button" onClick={getNextPage}>
Get Next Page
</button>
{data &&
data?.posts?.data?.map((post: any) => (
<div key={post.id}>
<h4>{post.title}</h4>
<p>{post.body}</p>
</div>
))}
</div>
)
So if I send a query with page === 1 I get posts from 1 to 5, if page === 2 - posts from 6 to 10 and so on.
The problem is that if for example I send request in next sequence
on last request Apollo performs network request, despite data for that that request is already in cache So my questions actually are:
I think it should be somehow configured in cache typePolicies but haven't found a way to make it work - despite data is in cache( I can track it with browser extension) it is not returned in {data}=useQuery :/ Here is how my cache config looks like.
export const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
posts: {
merge(existing, incoming) {
return [ ...existing,...incoming ]
}
}
}
}
}
})
Upvotes: 0
Views: 1039
Reputation: 7666
So there are two types of pagination. In the first pagination, the "pages" are somehow known to the user and the user navigates through these via the UI. This seems to be what you want to do:
I would propose to keep it simple: Change the state variables, pass them into useQuery
and render the results. Apollo will run the query again with the new page value every time the variables change. If Apollo has seen the same variables before (you go back to the previous page), Apollo can return the result from cache.
export const GET_POSTS = gql`
query GetPosts($options: PageQueryOptions!) {
posts(options: $options) {
data {
id
title
body
}
}
}
`
const Posts = (): JSX.Element => {
const [page, setPage] = useState<number>(1)
const { data } = useQuery(GET_POSTS, {
variables: {
options: {
paginate: {
page,
limit: 5,
},
},
},
nextFetchPolicy: "cache-first"
})
return (
<div>
<ListOfPosts {...{data,page,setPage }} />
</div>
)
}
const ListOfPosts = ({ data, page, setPage }) => {
const getNextPage = (): void => setPage((p: number) => p + 1);
const getPrevPage = (): void =>
setPage((p: number) => (p === 0 ? p : p - 1))
return (
<div>
<p>current page{page}</p>
<button type="button" onClick={getPrevPage}>
Get Prev Page
</button>
<button type="button" onClick={getNextPage}>
Get Next Page
</button>
{data &&
data?.posts?.data?.map((post: any) => (
<div key={post.id}>
<h4>{post.title}</h4>
<p>{post.body}</p>
</div>
))}
</div>
)
}
Merging the cache is only relevant when you want to continuously show results after another. Things like "load more" or "infinite scrolling". This means you want to continue adding to your result list. You would add more and more posts to the view and the old pages don't disappear. This is what fetchMore
is designed for. If you want to do that have a look at the docs and this part specifically. Your problem is that you are currently mixing both approaches, which probably leads to weird results.
Upvotes: 2