从零开始在ReactJS中实现无限滚动(不依赖第三方库)
React 从零实现无限滚动(无第三方库)
核心思路
通过状态控制当前渲染的条目数量,监听页面滚动事件,当滚动到接近底部时,增加显示的条目数,实现分批加载效果。
具体实现步骤
1. 添加状态管理
在组件中新增状态控制显示条目数和加载状态,同时保留你的原始数据状态:
import { useState, useEffect, useRef } from 'react'; function YourComponent() { const [data, setData] = useState([]); // 你的原始JSON数据 const [visibleItems, setVisibleItems] = useState(10); // 初始显示10条,可自定义 const [isLoading, setIsLoading] = useState(false); const scrollRef = useRef(null); // 可选,用于监听容器内滚动 // 加载JSON数据的逻辑 useEffect(() => { const fetchData = async () => { const res = await fetch('/your-data-source.json'); const jsonData = await res.json(); setData(jsonData); }; fetchData(); }, []); // 后续逻辑... }
2. 实现滚动监听逻辑
添加滚动监听,判断是否到达加载触发点,触发时增加显示条目数:
useEffect(() => { const handleScroll = () => { // 正在加载或已显示全部数据时,直接返回 if (isLoading || visibleItems >= data.length) return; // 计算页面滚动参数(如果是容器内滚动,替换为scrollRef.current的属性) const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight; const clientHeight = document.documentElement.clientHeight || window.innerHeight; // 距离底部200px时触发加载(可自定义触发距离) if (scrollTop + clientHeight >= scrollHeight - 200) { setIsLoading(true); // 模拟加载延迟(实际项目中如果是异步请求新数据,这里替换为请求逻辑) setTimeout(() => { // 每次加载10条,不超过总数据量 setVisibleItems(prev => Math.min(prev + 10, data.length)); setIsLoading(false); }, 500); } }; window.addEventListener('scroll', handleScroll); // 组件卸载时清理监听 return () => window.removeEventListener('scroll', handleScroll); }, [isLoading, visibleItems, data.length]);
3. 修改渲染逻辑
只渲染visibleItems数量的条目,替换你原来的全量渲染代码:
return ( <div ref={scrollRef}> {/* 如果是容器内滚动,给容器添加这个ref */} {data.slice(0, visibleItems).map((conto) => ( <Suspense key={conto._uid} fallback={<p>Loading...</p>}> <Conto blok={conto} data={data} ITEuro={ITEuro} deposit={deposit} handleToggleFavourite={handleToggleFavourite} isFavourited={isFavourited} depositQuantity={depositQuantity} /> </Suspense> ))} {/* 加载状态提示 */} {isLoading && <p>加载更多...</p>} {/* 无更多数据提示 */} {visibleItems >= data.length && !isLoading && <p>已加载全部数据</p>} </div> );
4. 容器内滚动适配(可选)
如果列表在固定高度的容器内滚动,只需修改滚动监听的目标元素:
useEffect(() => { const container = scrollRef.current; if (!container) return; const handleScroll = () => { if (isLoading || visibleItems >= data.length) return; const { scrollTop, scrollHeight, clientHeight } = container; if (scrollTop + clientHeight >= scrollHeight - 200) { setIsLoading(true); setTimeout(() => { setVisibleItems(prev => Math.min(prev + 10, data.length)); setIsLoading(false); }, 500); } }; container.addEventListener('scroll', handleScroll); return () => container.removeEventListener('scroll', handleScroll); }, [isLoading, visibleItems, data.length]);
关键优化点
- 防抖处理:如果滚动事件触发过于频繁,可给
handleScroll添加防抖逻辑(比如用setTimeout限制100ms内只触发一次),减少性能消耗。 - 边界判断:始终用
Math.min控制visibleItems不超过总数据长度,避免数组越界报错。 - 内存清理:组件卸载时务必移除滚动监听,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Michele Bordiga
相关产品推荐
相关产品推荐

