如何解决ApolloClient V3 with React:缓存和重用 fetchMore 查询的结果
我有一个使用 React、TS 和 Apollo 构建的小型学习项目。 作为后端,我使用 https://graphqlzero.almansi.me/
我要找的结果是:
这是我的容器
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>
)
}
和帖子列表
const listofPosts = ({ data,setPage }) => {
const getNextPage = (): void => {
fetchMore({
variables: {
options: {
paginate: {
page: page + 1,})
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>
)
因此,如果我发送带有 page === 1 的查询,我会收到从 1 到 5 的帖子,如果 page === 2 - 从 6 到 10 的帖子等等。
问题是,例如,如果我在下一个序列中发送请求
- page === 1(最初由 useQuery 发送)
- page === 2(使用 fetchMore 发送)
- page === 3(使用 fetchMore 发送)
- page === 2(使用 fetchMore 发送)
在最后一个请求 Apollo 执行网络请求,尽管该请求的数据已经在缓存中 所以我的问题实际上是:
- 如何配置 Apollo 缓存以返回所需的数据,而无需从服务器重新获取数据
- 如何使该数据“无效”并告诉 Apollo 我需要刷新该特定数据部分?
我认为它应该以某种方式在缓存 typePolicies 中进行配置,但还没有找到使其工作的方法 - 尽管数据在缓存中(我可以使用浏览器扩展跟踪它)它没有在 {data}=useQuery 中返回: / 这是我的缓存配置的样子。
export const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
posts: {
merge(existing,incoming) {
return [ ...existing,...incoming ]
}
}
}
}
}
})
解决方法
所以有两种类型的分页。在第一个分页中,“页面”以某种方式为用户所知,用户通过 UI 浏览这些页面。这似乎是您想要做的:
我建议保持简单:更改状态变量,将它们传递给 useQuery
并呈现结果。每次变量更改时,Apollo 都会使用新的页面值再次运行查询。如果 Apollo 之前看到过相同的变量(返回上一页),Apollo 可以从缓存中返回结果。
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,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>
)
}
合并缓存仅在您希望连续显示结果时才有意义。诸如“加载更多”或“无限滚动”之类的东西。这意味着您要继续添加到结果列表中。您会向视图中添加越来越多的帖子,而旧页面不会消失。这就是 fetchMore
的设计目的。如果您想这样做,请查看文档和 this part specifically。您的问题是您目前正在混合使用这两种方法,这可能会导致奇怪的结果。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。