如何用RTK Query合并分页数据实现无限滚动?
解决RTK Query无限滚动分页的合并问题
你遇到的核心问题是缓存结构不匹配:服务器返回的是嵌套结构(response.data.data为列表、response.data.last_page为分页信息),但你直接使用了默认缓存存储逻辑,导致merge时拿到的不是数组而是整个响应对象,自然无法用数组方法操作。
步骤1:统一缓存数据结构
先用transformResponse把服务器返回的数据转换成包含列表和分页元数据的固定结构,让缓存内容格式统一:
query: ({ accountId, page }) => ({ url: `/api/transactions/account/${accountId}`, method: 'get', params: { page } }), transformResponse: (response) => { return { items: response.data.data, // 实际交易列表数组 lastPage: response.data.last_page, // 总页数 currentPage: response.data.current_page // 当前页码(可选) } },
步骤2:修正缓存分组逻辑
你之前的serializeQueryArgs只返回endpointName,会导致不同accountId的请求共用同一缓存,这显然不合理。改成按accountId分组:
serializeQueryArgs: ({ queryArgs }) => { // 同一个accountId的请求归为同一缓存条目,不同accountId分开存储 return `transactions-${queryArgs.accountId}` },
步骤3:正确实现merge方法
现在缓存结构是{ items: [], lastPage: number },merge时需要把新页面的列表数据追加到现有列表,同时保留总页数:
merge: (currentCache, newData) => { // 追加新页面的列表项到现有缓存 currentCache.items.push(...newData.items) // 总页数直接覆盖(因为总页数不会随页码变化) currentCache.lastPage = newData.lastPage },
步骤4:调整请求触发逻辑
确保只有当accountId变化,或同一accountId下页码变化时才重新请求:
forceRefetch({ currentArg, previousArg }) { return ( currentArg.accountId !== previousArg?.accountId || currentArg.page !== previousArg?.page ) },
组件中判断是否停止请求
在组件里通过缓存的lastPage和当前页码判断是否还有更多数据:
const { data, fetchNextPage, isFetching } = useGetTransactionsQuery( { accountId: 123, page: currentPage }, { skip: !accountId } ) // 判断是否还有下一页可加载 const hasMore = data?.currentPage < data?.lastPage // 滚动到底部时触发下一页请求 const handleScroll = () => { if (hasMore && !isFetching) { fetchNextPage({ page: currentPage + 1 }) } }
之前报错的原因
- 第一个错误:
currentCache.push(...newItems),因为currentCache是服务器返回的完整响应对象(不是数组),没有push方法;同时newItems也是完整响应对象,不是可展开的数组。 - 第二个错误:
return [...currentCache, ...newItems],因为currentCache是对象而非可迭代的数组,无法用数组展开语法。
通过transformResponse统一缓存结构后,merge操作的是我们定义的标准化对象,就能正确实现数据追加了。
内容的提问来源于stack exchange,提问作者maganthro
相关产品推荐
相关产品推荐

