当 scrollTop 为零时,渲染后的反应滚动位置



我试图理解当可滚动div 中的数据发生变化时 react 的行为。

如果新数据包含一些当前可见的项目,react 将管理滚动位置以保持这些元素可见。

想象一下两组元素:a,b,c,d,e,f,g,h,if,g,h,i,j,k,l,m以及一个容器div,在垂直可滚动列表中显示它们,足够大,一次只能显示两个元素。

如果我向下滚动到元素f然后更改数据,元素f仍将是可见的。我相信这是有效的,因为每个元素都有自己的唯一键。

如果滚动位置为 0,则行为会有所不同:渲染新元素后,如果我改回第一组,滚动将仍然为零而不是f。如果您尝试向下滚动一个像素,则按预期工作。

这里有一个完整的最小工作示例:https://codepen.io/depsir/pen/OGGZPd

所以两个问题:

  1. 反应是这样做的吗?如果是这样,是否有任何关于此行为的文档?
  2. 即使scrollTop = 0,如何使渲染中的常见可见元素保持不变?


编辑:我发现该示例的行为在浏览器之间是不同的:Firefox Mobile和safari在任何情况下都保持滚动位置固定。

我发现这种行为与浏览器有关,所以现在我可以回答我的第一个问题:

反应是这样做的吗?如果是这样,是否有任何关于此行为的文档?

不,浏览器是否做所有事情。你可以简单地用 DOM API 试试这个:

// given a list of elements, in a scrollable container, 
// add a new element at first position
const list = document.getElementById("yourListId")  
list.insertBefore(getNewElement(), list.childNodes[0])

在这里你可以找到一个工作的例子:https://codepen.io/depsir/pen/GaRwWa

至于问题二,由于 react 什么都不做,很明显,这种行为必须手动管理。

您可以尝试传递keyindex以外的唯一值,它可以是key和任何随机值的相同组合,例如new Date() + index。不建议使用 itrator 作为 react 的key道具,你也可以看看这里

你可以试试

{state.map((k) => { var d = new Date(); return(<Element key={d +k} id={k} />)})}

{state.map((k) => { var random = Math.random(); return(<Element key={random +k} id={k} />)})}

这将尝试将滚动位置保留在您离开的位置。

如果它在scrollTop == 0不起作用,那么只需让它始终更:)。这是一个笨拙的解决方案,但它对我来说非常有效。

function InfiniteScroll(){
/* ... */
const ref = React.useRef()
React.useEffect(() => {
const handle = () => {
if(ref.current.scrollTop === 0){
ref.current.scrollTop = 1;
}
};
handle();
ref.current.addEventListener('scroll', handle)
return () => {
ref.current.removeEventListener('scroll', handle)
}
}, [])
return (
/* ... */
<div className='scroller' ref={ref}>
/* ... */
);
}

演示:https://codepen.io/anon/pen/KLdXKZ

您甚至可以在顶部添加边距以获得真正的像素完美效果。

最新更新