React滚动加载产品问题:如何实现初始10条+滚动触发加载10条
修复无限滚动初始加载全部数据的问题
你的问题核心在于初始请求一次性获取了所有产品,而非分页加载。要实现「初始加载10条,滚动到底部再加载10条」的效果,需从「前端分页请求」和「滚动触发逻辑优化」两方面修改:
1. 后端API支持分页参数(必要前提)
首先需要你的后端接口支持分页,接收page(页码)和limit(每页数量)参数,返回对应页的产品数据,以及总页数/总产品数(用于判断是否还有更多数据)。示例返回格式:
{ "products": [/* 当前页10条产品数据 */], "totalPages": 2, // 总页数 "totalCount": 20 // 总产品数 }
2. 前端代码修改
调整状态管理
新增分页相关状态,替换原有的productCount:
const Products = ({ cat, filters, sort }) => { const [products, setProducts] = useState([]); const [filteredProducts, setFilteredProducts] = useState([]); const [currentPage, setCurrentPage] = useState(1); // 当前请求页码 const [isLoading, setIsLoading] = useState(false); // 加载状态,避免重复请求 const [hasMore, setHasMore] = useState(true); // 是否还有更多数据可加载 const myRef = useRef(null);
修改初始请求逻辑,实现分页加载
将一次性请求所有产品改为分页请求,初始仅请求第1页(10条):
// 切换分类时重置分页状态 useEffect(() => { setCurrentPage(1); setProducts([]); setHasMore(true); }, [cat]); useEffect(() => { const getProducts = async () => { if (!hasMore) return; // 无更多数据时终止请求 setIsLoading(true); try { // 拼接分页参数 const url = cat ? `http://localhost:5000/api/products?category=${cat}&page=${currentPage}&limit=10` : `http://localhost:5000/api/products/?page=${currentPage}&limit=10`; const res = await axiosInstance.get(url); // 追加新数据,而非替换原有数据 setProducts(prevProducts => [...prevProducts, ...res.data.products]); // 判断是否还有更多数据(总页数大于当前页) setHasMore(res.data.totalPages > currentPage); } catch (err) { console.error('加载产品失败:', err); } finally { setIsLoading(false); } }; getProducts(); }, [cat, currentPage]); // 页码变化时自动请求下一页
优化滚动触发逻辑
添加加载状态和无更多数据的判断,避免重复请求和无效触发:
const handleScroll = () => { // 加载中或无更多数据时,不触发新请求 if (isLoading || !hasMore) return; if ( myRef.current && // 加100px偏移量,提前触发加载提升体验 myRef.current.getBoundingClientRect().bottom <= window.innerHeight + 100 ) { setCurrentPage(prevPage => prevPage + 1); } }; useEffect(() => { window.addEventListener("scroll", handleScroll); return () => { window.removeEventListener("scroll", handleScroll); }; }, [isLoading, hasMore]); // 依赖加载状态和是否有更多数据
渲染逻辑说明
现在products数组是累计加载的,渲染时直接使用该数组即可。如果需要过滤/排序,基于products处理filteredProducts:
// 示例:根据filters和sort处理过滤排序 useEffect(() => { let result = [...products]; // 应用过滤逻辑 if (filters) { // 你的过滤代码 } // 应用排序逻辑 if (sort) { // 你的排序代码 } setFilteredProducts(result); }, [products, filters, sort]);
关键修复点总结
- 从「一次性获取全部数据」改为「分页请求数据」,初始仅加载第1页
- 用
currentPage控制请求页码,滚动到底部时递增页码触发下一页请求 - 添加
isLoading和hasMore状态,避免重复请求和无效触发 - 切换分类时重置分页状态,保证新分类从第1页开始加载
内容的提问来源于stack exchange,提问作者Ilan Edri
相关产品推荐
相关产品推荐

