React中条件渲染加载更多元素时IntersectionObserver不触发问题
问题核心原因
你遇到的问题本质是条件渲染导致被IntersectionObserver监听的DOM节点不存在,或监听逻辑没有和节点渲染时机同步:
- 如果你给
Loading...外层加了仅在加载时才渲染的判断,那么非加载状态下被监听的节点直接从DOM树中移除,IntersectionObserver没有可监听的目标,自然不会触发 - 如果你用普通ref + 初始化只执行一次的useEffect绑定监听,首次渲染时如果节点还没渲染出来,ref是空值,监听逻辑根本没有生效,后续节点渲染出来也不会自动重新绑定
修复方案
1. 改用回调Ref绑定监听,保证节点渲染时自动绑定监听
用useCallback包裹ref回调逻辑,只要被监听的节点渲染到页面上,就会自动执行回调完成监听绑定,同时会在节点销毁前自动清理旧的监听实例,避免内存泄漏。
import { useState, useRef, useCallback, useEffect } from 'react'; function App() { const [page, setPage] = useState(1); const [isLoading, setIsLoading] = useState(false); const [numberOfPages, setNumberOfPages] = useState(0); const [listData, setListData] = useState([]); const observer = useRef(null); // 回调Ref,节点渲染时自动绑定监听 const loadMoreRef = useCallback(node => { // 正在加载中时不重复绑定 if (isLoading) return; // 先销毁之前的监听实例 if (observer.current) observer.current.disconnect(); observer.current = new IntersectionObserver(entries => { // 只有节点进入视口、还有下一页、非加载状态时才触发加载 if (entries[0].isIntersecting && page < numberOfPages && !isLoading) { setIsLoading(true); // 调用接口拉取下一页数据 fetch(`你的接口地址?page=${page + 1}`) .then(res => res.json()) .then(data => { setListData(prev => [...prev, ...data.list]); setNumberOfPages(data.totalPages); setPage(prev => prev + 1); setIsLoading(false); }); } }); // 节点存在时启动监听 if (node) observer.current.observe(node); }, [isLoading, page, numberOfPages]); // 首次加载第一页数据 useEffect(() => { setIsLoading(true); fetch(`你的接口地址?page=1`) .then(res => res.json()) .then(data => { setListData(data.list); setNumberOfPages(data.totalPages); setIsLoading(false); }); }, []); return ( <div className="App"> {/* 表格/列表内容 */} {listData.map(item => ( <div key={item.id} className="list-item">{item.content}</div> ))} {/* 监听节点:只要还有下一页就保留DOM,仅加载时显示Loading文本 */} {page < numberOfPages && ( <div ref={loadMoreRef} className="load-more-trigger"> {isLoading ? "Loading..." : null} </div> )} </div> ); }
2. 调整条件渲染逻辑
不要把加载节点的渲染和isLoading状态绑定,只要还有下一页数据,就保留这个监听节点的DOM存在:
- 加载中时节点内显示
Loading...文本 - 非加载状态下可以留空或者设置成高度极小的透明占位元素,不影响视觉效果,同时保证IntersectionObserver有可监听的目标
- 只有当前页等于总页数时,才销毁这个节点,停止触发加载逻辑
注意事项
- 每次绑定新的监听实例前,必须调用
disconnect销毁旧的实例,避免重复监听 - 触发加载的判断里必须加上
!isLoading的校验,避免同一时间发起多个重复请求 - 接口返回数据后要及时更新
isLoading状态,避免后续监听被阻塞
内容的提问来源于stack exchange,提问作者jarivak
相关产品推荐
相关产品推荐

