ReactJS:双向无限滚动建模

2022-08-30 05:19:19

我们的应用程序使用无限滚动来导航异构项目的大型列表。有一些皱纹:

  • 我们的用户通常会有一个包含 10,000 个项目的列表,并且需要滚动浏览 3k+。
  • 这些都是丰富的项目,因此在浏览器性能变得不可接受之前,我们只能在DOM中拥有几百个。
  • 这些物品的高度各不相同。
  • 这些项目可能包含图像,我们允许用户跳转到特定日期。这很棘手,因为用户可以跳到列表中的某个点,我们需要在视区上方加载图像,这将在加载内容时将其向下推。如果不处理,则意味着用户可能会跳转到某个日期,但随后会被转移到较早的日期。

已知的不完整解决方案:

  • (反应无限滚动)- 这只是一个简单的“当我们触底时加载更多”组件。它不会剔除任何DOM,因此它将在数千个项目上死亡。

  • (使用 React 滚动位置)- 显示如何在顶部插入底部插入时存储和恢复滚动位置,但不能同时存储和恢复滚动位置。

我不是在寻找完整解决方案的代码(尽管那会很棒)。相反,我正在寻找“React方式”来模拟这种情况。滚动位置是否为状态?我应该跟踪哪个州才能保留我在列表中的位置?我需要保持什么状态,以便在滚动到所渲染内容的底部或顶部附近时触发新的渲染?


答案 1

这是无限表和无限滚动方案的混合。我发现的最好的抽象如下:

概述

创建一个包含所有子项的数组的组件。由于我们不渲染它们,因此仅分配它们并丢弃它们真的很便宜。如果 10k 分配太大,则可以改为传递一个函数,该函数采用一个范围并返回元素。<List>

<List>
  {thousandelements.map(function() { return <Element /> })}
</List>

您的组件正在跟踪滚动位置,并且仅呈现视图中的子项。它在开头添加一个大的空 div,以伪造未呈现的先前项。List

现在,有趣的部分是,一旦渲染了组件,您就可以测量其高度并将其存储在.这使您可以计算垫片的高度,并知道视图中应显示多少个元素。ElementList

图像

您是说,当图像加载时,它们会使所有内容“跳”下来。此问题的解决方案是在 img 标记中设置图像尺寸:。这样,浏览器就不必等到下载它,然后才知道它将显示什么大小。这需要一些基础设施,但这确实是值得的。<img src="..." width="100" height="58" />

如果您无法提前知道大小,请向图像添加侦听器,并在加载图像时测量其显示的尺寸并更新存储的行高度并补偿滚动位置。onload

跳到随机元素

如果您需要跳转到列表中的随机元素,则需要一些滚动位置的技巧,因为您不知道两者之间元素的大小。我建议你做的是平均你已经计算过的元素高度,并跳到最后一个已知高度+(元素数量*平均值)的滚动位置。

由于这并不精确,因此当您回到上一个已知的良好位置时,它会导致问题。发生冲突时,只需更改滚动位置即可修复它。这将使滚动条移动一点,但不应该对他/她产生太大影响。

反应细节

您希望为所有渲染的元素提供一个键,以便跨渲染维护它们。有两种策略:(1)只有n个键(0,1,2,...n) 其中 n 是可以显示并使用其位置模数 n 的最大元素数。(2) 每个元素具有不同的键。如果所有元素共享类似的结构,最好使用(1)来重用它们的DOM节点。如果他们不这样做,则使用(2)。

我只有两段 React 状态:第一个元素的索引和显示的元素数量。当前滚动位置和所有元素的高度将直接附加到 。使用时,您实际上是在进行重新渲染,这应该仅在范围更改时发生。thissetState

这是一个无限列表的示例,使用我在此答案中描述的一些技术。这将是一些工作,但 React 绝对是实现无限列表的好方法:)


答案 2

看看 http://adazzle.github.io/react-data-grid/index.html#这看起来像一个功能强大且高性能的数据网格,具有类似Excel的功能和延迟加载/优化的渲染(对于数百万行),具有丰富的编辑功能(MIT许可)。尚未在我们的项目中尝试过,但很快就会这样做。

搜索此类内容的一个很好的资源也是 http://react.rocks/ 在这种情况下,标签搜索很有帮助:http://react.rocks/tag/InfiniteScroll