如何在函数中调用RTK Query实现React无限滚动?
解决方案
核心问题分析
你的代码存在几个关键问题导致按需加载失效:
- 没有利用RTK Query的异步返回结果,反而自己模拟了
loadItems请求逻辑,完全绕开了RTK Query的分页能力 - 本地状态管理混乱,重复维护
items、dataToDisplay等状态,和RTK Query的返回数据脱节 - 直接修改状态数组(
items.splice(0))不符合React状态更新规范,无法触发组件重渲染
重构后的代码实现
import { useState, useEffect } from 'react'; import { useGetAllSessionsPaginatedQuery } from './your-api-slice-path'; // 替换为你的API切片实际路径 const ARRAY_SIZE = 5; // 保持你定义的每页数据量常量 export const useLoadItems = (type: dataType = dataType.friends) => { // 维护分页参数:offset从0开始,每次加载后累加每页数量 const [paginationParams, setPaginationParams] = useState({ offset: 0, limit: ARRAY_SIZE, }); // 维护合并后的所有数据 const [items, setItems] = useState<Item[]>([]); // 判断是否还有下一页 const [hasNextPage, setHasNextPage] = useState(true); // 调用RTK Query,分页参数变化时自动触发新请求 const { data, isLoading, isFetching, isError, error } = useGetAllSessionsPaginatedQuery(paginationParams, { keepUnusedDataFor: 0, // 根据需求调整缓存时长 }); // 当RTK Query返回新数据时,合并到现有列表中 useEffect(() => { if (data?.length) { // 避免重复添加数据(防止重复请求导致的重复条目) const lastItemKey = items[items.length - 1]?.key; const newLastKey = paginationParams.offset + data.length - 1; if (lastItemKey !== newLastKey) { setItems(prev => [ ...prev, ...data.map((item, idx) => ({ key: paginationParams.offset + idx, value: item, })) ]); // 判断是否还有下一页:返回数据长度等于每页限制则还有更多,否则没有 setHasNextPage(data.length === paginationParams.limit); } } }, [data, paginationParams.offset, items]); const loadMore = async (reset: boolean = false) => { if (reset) { // 重置所有状态,回到初始页 setItems([]); setPaginationParams({ offset: 0, limit: ARRAY_SIZE }); setHasNextPage(true); return; } // 正在请求或无更多数据时直接返回 if (isFetching || !hasNextPage) return; // 更新offset,触发RTK Query的下一页请求 setPaginationParams(prev => ({ ...prev, offset: prev.offset + prev.limit, })); }; // 合并加载状态:首次加载用isLoading,后续加载用isFetching const loading = isLoading || isFetching; return { loading, items, hasNextPage, error, loadMore, // 保留调整每页数量的能力,同步更新分页参数 setArraySize: (size: number) => { setPaginationParams(prev => ({ ...prev, limit: size })); }, }; };
关键优化说明
- RTK Query自动触发请求:分页参数变化时,RTK Query自动发起新请求,无需手动处理异步逻辑
- 数据合并逻辑:每次请求返回新数据后,将其追加到现有列表,实现无限滚动的累加效果
- 下一页判断:通过返回数据长度与每页限制的对比判断是否还有更多数据(如果后端返回
hasNextPage字段,直接使用该字段更准确) - 复用RTK Query状态:直接使用RTK Query提供的
isLoading、isFetching等状态,避免重复维护本地状态 - 规范状态更新:使用React状态更新函数修改状态,避免直接操作原数组
与react-infinite-scroll-hook配合示例
在组件中直接调用封装好的hook即可:
import useInfiniteScroll from 'react-infinite-scroll-hook'; const ItemsList = () => { const { loading, items, hasNextPage, loadMore } = useLoadItems(); const [ref] = useInfiniteScroll({ loading, hasNextPage, onLoadMore: loadMore, rootMargin: '0px 0px 100px 0px', // 距离底部100px时触发加载 }); return ( <div ref={ref}> {items.map(item => ( <div key={item.key}>{item.value}</div> ))} {loading && <div>加载中...</div>} {!loading && !hasNextPage && <div>没有更多数据了</div>} </div> ); };
内容的提问来源于stack exchange,提问作者Camille Gallet
相关产品推荐
相关产品推荐

