Apollo-Angular GraphQL Client分页与FetchMore实现问题求助
Apollo-Angular Offset-Limit分页异常问题解决
问题原因分析
- 实体主键缺失配置:你的
User类型未在Apollo缓存中指定主键字段(默认Apollo会寻找id字段,但你的User用的是uid)。当使用offsetLimitPagination()时,缓存合并数据无法识别重复的User条目,导致新旧数据重复追加,出现初始查询数据重复、fetchMore后数据无更新的情况。 - 缓存合并逻辑失效:没有主键的情况下,
offsetLimitPagination()的默认merge策略会直接将新数据追加到现有缓存数组中,即使是重复条目也无法去重;而移除该配置后,缓存没有分页合并策略,fetchMore的结果不会写入缓存,因此valueChanges订阅不会触发更新。 - fetchMore变量完整性问题:fetchMore调用时未显式传递所有查询变量(如
search、orderBy),可能导致缓存字段的键不匹配,无法正确合并新数据。
解决方案
1. 配置实体主键
在InMemoryCache的typePolicies中为User类型指定主键uid,让Apollo能正确识别唯一实体:
// app.module.ts cache: new InMemoryCache({ typePolicies: { User: { keyFields: ['uid'], // 明确User实体的主键为uid }, Query: { fields: { myFriends: offsetLimitPagination(), } } } })
2. 确保fetchMore变量完整性
调用fetchMore时显式传递所有必要变量(与初始查询保持一致),避免缓存键不匹配:
// friends.component.ts handleInfiniteScroll(event: Event) { this.offset += 10; this.query.fetchMore({ variables: { limit: 10, offset: this.offset, search: "", // 复用组件内的search变量,比如this.search orderBy: [{ firstName: 'ASC' }], // 复用组件内的sort变量,比如this.sort }, // 可选:自定义updateQuery确保数据正确合并(如果默认merge仍有问题) updateQuery: (prevResult, { fetchMoreResult }) => { if (!fetchMoreResult) return prevResult; return { myFriends: [...prevResult.myFriends, ...fetchMoreResult.myFriends] }; } }); }
3. 调整fetchPolicy(可选)
将初始查询的fetchPolicy从network-only改为cache-and-network,既保证获取最新数据,又能正确利用缓存合并:
// friend.service.ts getFriends(limit?: number, offset?: number, search?: string, sort?: Sort[]) { return this.apollo.watchQuery<{ myFriends: User[] }>({ query: myFriendsQuery, variables: { limit: limit, offset: offset, search: search, orderBy: sort, }, fetchPolicy: 'cache-and-network', // 替换network-only }); }
验证步骤
- 配置User主键后,初始查询的重复数据会消失,因为Apollo会自动去重。
- 调用fetchMore后,订阅会触发,且
valueChanges返回的数据是初始数据+新分页数据的正确合并结果。 - 确认网络请求返回的分页数据与缓存合并后的结果一致。
内容的提问来源于stack exchange,提问作者Galen Howlett
相关产品推荐
相关产品推荐

