Anilist GraphQL分页查询Apollo缓存分离与合并问题咨询
解决方案
1. 让缓存区分ANIME与MANGA类型的Page数据
方案A:将media类型转为查询变量
把原查询中写死的type: "ANIME"/type: "MANGA"改成变量参数,这样不同类型的查询会因变量差异生成独立缓存条目:
统一查询模板:
query MediaPage($page: Int, $perPage: Int, $type: MediaType!) { Page(page: $page, perPage: $perPage) { media(type: $type) { id title { romaji } } } }
- Anime页面调用时,传入变量:
{ page: 1, perPage: 20, type: "ANIME" } - Manga页面调用时,传入变量:
{ page: 1, perPage: 20, type: "MANGA" }
Apollo会自动根据不同的$type变量生成独立缓存键,彻底避免缓存覆盖问题。
方案B:自定义缓存键函数(Apollo Client 3+)
若无法修改原有查询结构,可通过cacheKeyFn为Page对象生成包含媒体类型的唯一缓存键,在Apollo Client配置中添加:
const client = new ApolloClient({ uri: 'https://graphql.anilist.co', cache: new InMemoryCache({ cacheKeyFn: (obj, options) => { if (obj.__typename === 'Page') { // 从查询参数中提取媒体类型,生成唯一键 const mediaType = options.field?.args?.type || options.variables?.type; return `Page:${mediaType}:${obj.page || ''}`; } // 其他类型沿用默认逻辑 return defaultDataIdFromObject(obj); }, }), });
2. 分页时合并对应类型的media列表
方案A:fetchMore + updateQuery手动合并
分页加载时,通过fetchMore发起请求,并在updateQuery中手动将新数据追加到缓存列表:
// Anime页面示例 const { data, fetchMore } = useQuery(MediaPage, { variables: { page: 1, perPage: 20, type: "ANIME" }, }); const loadNextPage = () => { fetchMore({ variables: { page: data.Page.page + 1 }, updateQuery: (prevResult, { fetchMoreResult }) => { if (!fetchMoreResult) return prevResult; return { Page: { ...prevResult.Page, media: [...prevResult.Page.media, ...fetchMoreResult.Page.media], page: fetchMoreResult.Page.page, }, }; }, }); };
方案B:@connection指令自动处理分页
在查询中添加@connection指令,指定包含媒体类型的唯一连接名称,让Apollo自动合并分页数据:
query MediaPage($page: Int, $perPage: Int, $type: MediaType!) { Page(page: $page, perPage: $perPage) { media(type: $type) @connection(key: "MediaList_$type") { id title { romaji } } } }
key: "MediaList_$type"会自动代入$type变量,生成MediaList_ANIME和MediaList_MANGA两个独立缓存,Apollo会自动完成后续分页数据的合并,无需手动编写更新逻辑。
额外提示
- 不要用清空缓存的方式解决问题,这会导致重复请求,降低用户体验。
- 优先选择「方案1A + 方案2B」的组合,代码简洁且符合Apollo最佳实践。
内容的提问来源于stack exchange,提问作者Stas Motorny
相关产品推荐
相关产品推荐

