天天看点

译文:增强在 React 中渲染大型列表的方式

译文:增强在 React 中渲染大型列表的方式

介绍

在 React 中渲染大型列表对于开发人员来说可能是一项艰巨的任务。随着列表大小的增加,DOM(文档对象模型)树也会增长,从而导致渲染速度慢、滚动不流畅和内存使用率高等性能问题。在本文中,我们将讨论开发人员在渲染大型列表时面临的一些常见问题,以及可用于克服这些问题的各种解决方案。

问题陈述

为什么在 Web 浏览器中渲染大量列表是一项艰巨的任务?嗯,在渲染大量项目列表时需要考虑几个因素。首先是性能,随着屏幕上要渲染的元素数量增加,浏览器的渲染引擎开始遇到性能问题。这会导致渲染速度变慢,从而导致用户界面迟缓和用户体验不佳。

处理大量元素列表需要耗费大量计算资源。滚动浏览大型列表可能会让最终用户感到不爽,最糟糕的情况是,他们可能会看到一个完全无响应的页面。由于处理能力和内存有限,对手机等低端设备的负面影响会更大。

考虑到所有这些问题,作为软件开发人员,我们需要采用优化技术并选择适当的策略。

概括

本文主要讨论如何在 React 中渲染大量列表。首先,我们将定义大量列表的含义。然后,我们将研究一些可以采用的解决方案,以解决问题陈述中指出的问题。最后,我们将讨论在浏览器中渲染大量列表时需要牢记的几个关键事项。

庞大的清单是什么意思呢?

译文:增强在 React 中渲染大型列表的方式

图 1:渲染大量列表的代码片段

庞大列表的定义是动态的。它完全取决于最终用户的设备。如果他们都在高端计算机或移动设备上,那么在看到任何性能限制之前,您可以在页面上安全呈现的元素数量将非常高。

另一方面,如果您的最终用户的设备比较普通,内存和处理能力有限,则此阈值将小于上述阈值。随着现代浏览器的进步,您可以轻松加载大量 DOM 元素而不必担心太多,但即便如此,如果您开始渲染包含 1,000 行或更多行的订单列表,您可以认为它是巨大的。

如何解决 React 中渲染大型列表的问题?

如果您最终需要渲染数以万计的复杂列表项,则无论最终用户的硬件性能如何,您都不可避免地必须使用以下解决方案之一。首先,我们将从每个人都可以合并到其代码中的通用解决方案开始:

保持渲染树较小

译文:增强在 React 中渲染大型列表的方式

图 2:渲染树图解

总体而言,保持精简的渲染树可以提高整体性能,因为 DOM 元素越多,浏览器需要分配的空间就越多。此外,浏览器在布局阶段将花费更多时间。这在渲染大量列表时变得极为关键。即使减少一个 div 也能带来明显的性能差异。

最佳做法是使用最少数量的 DOM 元素来创建列表项,而不影响设计。

让我们来实验一下:

首先,我们将创建一个包含约 10,000 个元素的简单列表。以下是该列表的代码沙箱。

让我们来看看该页面的 Lighthouse 性能:

译文:增强在 React 中渲染大型列表的方式

图 3:海量列表的 Lighthouse 评分

首次内容绘制 0.9 秒
最大的内容丰富的油漆 3.0 秒
总阻塞时间 2.1 秒
总绩效得分 43

现在,让我们向列表项中添加一个 div 并获取所有性能数字。

以下是灯塔的表演:

译文:增强在 React 中渲染大型列表的方式

图 4:带有一个额外 div 的 Lighthouse 分数

首次内容绘制 1 秒
最大的内容丰富的油漆 3.3 秒
总阻塞时间 3.3 秒
总绩效得分 40

无限滚动

现在让我们进入实际的解决方案,其中第一个是使用无限滚动技术。用更简单的话来说,这种技术意味着只渲染填满整个页面长度所需的列表项,然后在用户向下滚动时添加更多项目。

我们可以使用react-infinite-scroller库来实现这一点。

以下是使用 react-infinite-scroller 实现的相同 10,000 个项目列表。

让我们看看它是如何影响我们的表现的:

译文:增强在 React 中渲染大型列表的方式

图 5:无限滚动的 Lighthouse 得分

首次内容绘制 1.0 秒
最大的内容丰富的油漆 2.5 秒
总阻塞时间 160毫秒
总绩效得分 78

我们的整体绩效滚动从基数43跃升至78,这是一个巨大的进步。

这是因为我们实际上将列表分成了很小的部分。我们不是一次性渲染所有 10,000 个项目,而是只渲染在用户视图中渲染页面部分所需的前几个项目。当用户向下滚动时,react-infinite-scroller 库会将更多项目添加到 DOM。

窗口化

解决该问题的另一个方法是使用窗口技​术。

窗口化(或虚拟化)是一种技术,您可随时仅渲染列表中用户可见的部分。与无限滚动不同,在窗口化中,DOM 始终具有恒定数量的元素。换句话说,我们仅渲染填充用户视野所需的元素,并从列表顶部和底部移除尚未出现在视图中的元素。

译文:增强在 React 中渲染大型列表的方式

图 6:窗口技术图示

当列表中的每个项目都有固定高度时,窗口化会大放异彩。这样,就可以根据滚动情况轻松计算出需要从 DOM 中添加或删除哪些项目。此外,无论用户滚动到哪里,页面的内存使用量都会保持不变,因为 DOM 元素的数量保持不变。

以下是使用 react-window 实现的相同 10,000 个项目列表。

让我们看看它是如何影响我们的表现的:

译文:增强在 React 中渲染大型列表的方式

图 7:带窗口的海量列表的 Lighthouse 得分

首次内容绘制 1.0 秒
最大的内容丰富的油漆 2.5 秒
总阻塞时间 190毫秒
总绩效得分 76

要记住的关键事项

使用这两种技术,您都无法执行浏览器搜索。换句话说,如果用户使用cmd + f搜索尚未呈现的文本,他们将看到 0 个匹配项(共 0 个)。为了防止这种情况,您应该在列表中添加自定义搜索或过滤选项。

与本机滚动相比,在 DOM 中添加/删除元素总是会出现轻微的延迟,但这仍然比您的应用程序最终因大量 DOM 元素而挂起要好。

创建您自己的解决方案

如果您希望保持解决方案轻量并且不想使用任何库,您还可以使用Intersection Observer API实现自己的 DOM 元素延迟加载。

首先,添加足够的组件来填充您的视口。使用 getBoundingClientRect 获取视口高度,并将其除以近似的最小项目高度。为此计数加 1 以获得更好的结果。现在在其下方添加一个虚拟组件(此组件不需要显示任何内容;它只需要存在于列表的底部)。将交集可观察对象附加到此组件,并且每当此组件在视图中时,将更多项目添加到列表中以在 DOM 中呈现。这样,您最终将开发一个简单的无限滚动解决方案。

结论

现在,您应该能够处理 React 应用程序中的大型列表。简而言之,您应该一次只渲染列表的一小部分,并确保视图中有足够的过滤器供用户对列表进行筛选。

作者:

Srijan Gulati

Srijan Gulati is a Senior Software Developer and the Frontend lead for Uber’s Crash analytics (Apps, services, and in-app bug reporter). He is passionate about responsive and accessible UX, problem-solving, and VIM.

Karan Verma

Karan Verma is a Senior Software Engineer and Frontend Developer specializing in data visualization at scale.

出处:https://www.uber.com/en-JP/blog/supercharge-the-way-you-render-large-lists-in-react/