React Photo Album无限滚动问题:新增图片后滚动位置重置求助
问题描述
我正在尝试为react-photo-album组件实现无限滚动功能。已通过在相册下方设置Intersection Observer实现滚动到底部时获取更多图片,但存在问题:当将新图片添加到状态并传入相册组件props后,组件会重新渲染并回到顶部。不想自行实现相册组件,因为难以处理不同尺寸、比例图片的响应式行列布局。
现有代码
import React, { useState, useCallback, useRef } from 'react'; import PhotoAlbum from 'react-photo-album'; const [images, setImages] = useState<ImageState[]>([]); const lastImageObserver = useRef<IntersectionObserver>(); const lastImageElementRef = useCallback( (node: any) => { if (lastImageObserver.current) lastImageObserver.current.disconnect(); lastImageObserver.current = new IntersectionObserver( (entries) => { if (entries[0].isIntersecting) { console.log('last image is intersecting'); if (currentPage < Math.ceil(totalImages / rowsPerPage)) { setCurrentPage((prevPage) => prevPage + 1); } } }, { threshold: 0.1, } ); if (node) lastImageObserver.current.observe(node); }, [currentPage, rowsPerPage] ); const fetchImages = useCallback(async () => { const result = await getPhotos( currentPage, rowsPerPage ); const newImages = result.images; setImages((prev) => [...prev, ...newImages]); }, [currentPage, totalImages]); return ( <div> <div> <PhotoAlbum layout="rows" photos={images} /> <div ref={lastImageElementRef} style={{ minHeight: '1px' }} ></div> </div> </div> )
解决方案
1. 保存并恢复全局滚动位置
在请求新图片前记录当前滚动位置,DOM更新完成后恢复该位置:
const fetchImages = useCallback(async () => { // 记录当前滚动位置 const scrollPosition = window.scrollY || document.documentElement.scrollTop; const result = await getPhotos(currentPage, rowsPerPage); setImages(prev => [...prev, ...result.images]); // 延迟恢复滚动,确保相册DOM已更新 setTimeout(() => { window.scrollTo(0, scrollPosition); }, 0); }, [currentPage, totalImages]);
2. 监听最后一张图片而非底部占位div
将Intersection Observer的监听目标改为相册的最后一张图片,减少布局变化带来的干扰:
return ( <PhotoAlbum layout="rows" photos={images} renderPhoto={({ photo, index }) => { // 仅给最后一张图片绑定监听ref const targetRef = index === images.length - 1 ? lastImageElementRef : undefined; return <img ref={targetRef} src={photo.src} alt={photo.alt} />; }} /> );
同时可以移除原来的底部占位div,避免额外的布局变动。
3. 针对局部滚动容器的处理
如果相册放在自定义滚动容器内,需要记录和恢复容器的滚动位置:
const albumContainerRef = useRef<HTMLDivElement>(null); const fetchImages = useCallback(async () => { if (!albumContainerRef.current) return; const scrollTop = albumContainerRef.current.scrollTop; const result = await getPhotos(currentPage, rowsPerPage); setImages(prev => [...prev, ...result.images]); setTimeout(() => { if (albumContainerRef.current) { albumContainerRef.current.scrollTop = scrollTop; } }, 0); }, [currentPage, totalImages]); // 渲染时给滚动容器添加ref return ( <div ref={albumContainerRef} style={{ overflowY: 'auto', height: '100vh' }} > <PhotoAlbum layout="rows" photos={images} /> </div> );
4. 优化组件重渲染
确保PhotoAlbum组件仅在images变化时重渲染:
- 检查父组件是否有不必要的重渲染,可通过
React.memo包裹父组件或相关子组件 - 确保
fetchImages、lastImageElementRef等回调的依赖项正确,避免不必要的更新
内容的提问来源于stack exchange,提问作者Alex K
相关产品推荐
相关产品推荐

