Apollo Client查询变量变更时缓存未更新,分页返回上页数据异常
问题原因
- 核心原因是你直接通过
window.location读取路由参数,该取值方式不是React响应式的,路由跳转时LinkList组件不会触发重渲染,page变量一直停留在组件首次挂载时的值,导致useQuery接收的variables始终没有更新,Apollo自然不会拉取对应页码的新数据,也不会从缓存中读取上一页的对应数据。 - 次要潜在原因:如果你的Apollo Client没有配置分页字段的缓存合并策略,不同页码的查询结果可能会互相覆盖,就算变量更新也会出现数据异常。
修复步骤
步骤1:替换路由参数读取逻辑
使用react-router提供的useParams钩子读取页码参数,确保路由变化时组件能响应式拿到最新页码,触发重渲染并更新查询变量。
步骤2:(可选)配置Apollo缓存策略
如果修改参数读取逻辑后仍有缓存问题,给分页字段配置合并策略,或者给useQuery指定合适的拉取策略。
修改后参考代码
import React from "react"; import Link from "./Link"; import { useQuery } from "@apollo/client"; import { useNavigate, useParams, useLocation } from "react-router-dom"; import { LINKS_PER_PAGE } from "../utilities/constants"; import FEED_QUERY from "../graphql/queries/feedLinks"; import getQueryVariables from "../utilities/getQueryVariables"; import getLinksToRender from "../utilities/getLinksToRender"; const LinkList = () => { const navigate = useNavigate(); const { pathname } = useLocation(); // 用useParams读取路由里的page参数,无需自行切割路径 const { page: pageParam } = useParams(); const page = parseInt(pageParam) || 1; const isNewPage = pathname.includes("new"); const pageIndex = (page - 1) * LINKS_PER_PAGE; const { data, loading, error} = useQuery(FEED_QUERY, { variables: getQueryVariables(isNewPage, page), // 如果还有缓存问题可以去掉下方注释,优先用缓存无匹配数据再发请求 // fetchPolicy: "cache-first" }); return ( <> {loading && <p>Loading...</p>} {error && <pre>{JSON.stringify(error, null, 2)}</pre>} {data && ( <> {getLinksToRender(isNewPage, data).map((link, index) => ( <Link key={link.id} link={link} index={index + pageIndex} /> ))} {isNewPage && ( <div className="flex ml4 mv3 gray"> <div className="pointer mr2" onClick={() => { if (page > 1) { navigate(`/new/${page - 1}`); } }} > Previous </div> <div className="pointer" onClick={() => { if (page < data.feed.count / LINKS_PER_PAGE) { const nextPage = page + 1; navigate(`/new/${nextPage}`); } }} > Next </div> </div> )} </> )} </> ); }; export default LinkList;
如果确认是缓存合并导致的问题,可在初始化Apollo Client时添加如下配置:
import { InMemoryCache, ApolloClient } from "@apollo/client"; const cache = new InMemoryCache({ typePolicies: { Query: { fields: { feed: { keyArgs: false, merge(existing = { links: [] }, incoming) { return { ...incoming, links: [...existing.links, ...incoming.links] } } } } } } }) const client = new ApolloClient({ // 其余客户端配置 cache })
内容的提问来源于stack exchange,提问作者Reem Obeid
相关产品推荐
相关产品推荐

