
React 中若需监听特定容器的滚动事件,应直接在该容器上使用 onScroll 事件处理器,而非监听 window;当滚动目标是内部 <div> 而非整个视口时,window.addEventListener('scroll') 不会触发,必须绑定到实际滚动容器上。
react 中若需监听特定容器的滚动事件,应直接在该容器上使用 `onscroll` 事件处理器,而非监听 `window`;当滚动目标是内部 `
在 React 应用中实现无限滚动(Infinite Scroll)时,一个常见误区是:误以为页面滚动就等于 window 滚动。实际上,你的代码中设置了 div.results-page 的 height: 100vh 和 overflow: scroll,这意味着滚动行为发生在该 <div> 内部——它才是真正的滚动容器(scrolling container),而 window 本身并未滚动。因此,通过 window.addEventListener('scroll', ...) 注册的监听器永远不会被触发。
✅ 正确做法是:将滚动监听绑定到实际滚动的 DOM 元素上。React 提供了原生支持的 onScroll 事件属性,可直接在 JSX 中声明:
<div
onScroll={handleInfiniteScrolling}
className="results-page"
style={{
height: '100vh',
overflow: 'auto', // 推荐使用 'auto' 替代 'scroll',避免始终显示滚动条
}}
>
{data.map((item) => (
<MainLayer key={item._id} props={item} />
))}
</div>⚠️ 注意事项:
- onScroll 是 React 合成事件,无需手动 addEventListener/removeEventListener,也无需 useEffect 副作用清理(除非你混合使用 ref + 原生事件);
- 若需获取滚动位置,可通过 event.target.scrollTop(对应 div 的滚动偏移)和 event.target.scrollHeight 获取容器总高度;
- 确保父级元素(如 html, body)无默认 margin 或 overflow: hidden,否则可能干扰滚动布局(示例中已添加 html, body { margin: 0; });
- 避免高频触发导致性能问题:对 handleInfiniteScrolling 添加防抖(debounce)或节流(throttle),或使用 IntersectionObserver 替代滚动监听(更推荐用于现代无限加载场景)。
? 补充建议(进阶优化):
为防止重复加载、提升体验,可在 handleInfiniteScrolling 中加入判断逻辑:
const handleInfiniteScrolling = (e: React.UIEvent<HTMLDivElement>) => {
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
// 当滚动到底部附近(例如剩余 100px 时)触发加载
if (scrollTop + clientHeight >= scrollHeight - 100 && !loading && hasMore) {
setLoading(true);
fetchMoreData().finally(() => setLoading(false));
}
};综上,无限滚动的关键在于明确滚动上下文:不是“页面是否在滚动”,而是“哪个元素在滚动”。绑定事件到正确的 DOM 节点,并结合合理的触发阈值与加载状态管理,才能构建稳定、高性能的无限加载体验。


















