React中向容器上下添加元素时如何保持滚动位置?
React双向无限滚动:顶部加载后滚动位置异常问题
需求说明
- 用户滚动到容器底部时加载新元素
- 同一时刻容器内元素不超过10个(优化渲染性能)
- 向上滚动到顶部时加载历史元素
问题描述
目前功能已基本实现,但存在核心问题:向上滚动加载并在列表头部添加历史元素后,滚动位置停留在顶部,不符合预期。
- 注:滚动到底部加载元素时无此问题,新元素渲染在底部后,滚动位置保持在列表中间,可继续滚动加载。
- 注2:此前底部加载也有类似问题,将
map的key从索引改为API返回的唯一id后解决,推测React通过key记忆元素位置,但顶部加载时该逻辑不生效,原因不明。
代码说明
Constants.pageSize为5,sendQuery根据传入页码返回包含5个元素的数组。
const Container = () => { const [pageNumber, setPageNumber] = useState(1) const [data, setData] = useState([]) const lastElemRef = useRef(null) const firstElemRef = useRef(null) const isFirstRender = useFirstRender() const pageNumberRef = useRef(pageNumber) useEffect(() => { if(pageNumberRef.current < pageNumber){ // next page sendQuery(pageNumber).then((res) => { const prevData = data.slice(-Constants.pageSize) setData([...prevData, ...res]) }) } else{ sendQuery(pageNumber-1).then((res) => { const prevData = data.slice(0, Constants.pageSize) setData([...res, ...prevData]) }) } pageNumberRef.current = pageNumber }, [pageNumber]) const callBack = useCallback((entries) => { const target = entries[0] if(target.target.id === "load-next" && target.isIntersecting && !isFirstRender){ setPageNumber(page => page + 1) } if(target.target.id === "load-prev" && target.isIntersecting && !isFirstRender){ setPageNumber(page => { if(page > 2){ return page-1 }else{ return page } }) } }, [isFirstRender, setPageNumber]) useEffect(() => { observer = new IntersectionObserver(callBack, {root: document.getElementById("container"), threshold: 0.5}) const lastElem = lastElemRef.current const firstElem = firstElemRef.current if(lastElem){ observer.observe(lastElem) observer.observe(firstElem) } return (() => { if(lastElem){ observer.unobserve(lastElem) observer.observe(firstElem) } }) }, [callBack]) return ( <div id="container" className="container"> <div ref={firstElemRef} id="load-prev"></div> { data.map((post, index) => { return ( <Post image={post.urls.regular} by={post.user.first_name} key={post.id} /> ) }) } <div ref={lastElemRef} style={{height: "300px"}} id="load-next"></div> </div> ) }
内容的提问来源于stack exchange,提问作者Cam4phor
相关产品推荐
相关产品推荐

