带有 React 的 ApolloClient V3:缓存和重用 fetchMore 查询的结果
Posted
技术标签:
【中文标题】带有 React 的 ApolloClient V3:缓存和重用 fetchMore 查询的结果【英文标题】:ApolloClient V3 with React: Caching and re-using result of fetchMore query 【发布时间】:2021-10-02 10:59:40 【问题描述】:我有一个使用 React、TS 和 Apollo 构建的小型学习项目。 作为后端,我使用https://graphqlzero.almansi.me/
我要找的结果是:
-
按页获取帖子,每页 5 个
重复使用之前获取的数据
这是我的容器
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>
)
和 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 pagepage</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 ]
)
【问题讨论】:
【参考方案1】:所以有两种类型的分页。在第一个分页中,“页面”以某种方式为用户所知,用户通过 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, 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 pagepage</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。您的问题是您目前正在混合使用这两种方法,这可能会导致奇怪的结果。
【讨论】:
以上是关于带有 React 的 ApolloClient V3:缓存和重用 fetchMore 查询的结果的主要内容,如果未能解决你的问题,请参考以下文章
React 和 ApolloClient:网络错误:forward(...).subscribe 不是函数
将 mutate() 从 ApolloClient 移动到 React 组件的正确方法?
apolloClient.query 不使用中间件,而 <Query /> 使用
带有 React 的 Apollo 客户端 2 无法进行查询