对于一个长列表,比如1000个数组的数据结构,如果要同时渲染这1000个数据,生成对应的1000个原生dom,我们都知道原生的DOM元素很复杂,如果通过生成这么多DOM元素来实现长列表,很可能会导致网页无响应。贯穿React核心的是“虚拟dom”。我们还可以使用虚拟列表来优雅地优化长列表。原生dom呈现长列表。-tiny-virtual-list优化长列表本文原文地址发表在我的博客:https://github.com/forthealll...欢迎star和fork~本文用例代码地址是:https://github.com/forthealll...1.原生DOM渲染长列表的缺陷首先,我们在React项目中尝试在没有任何优化的情况下一次渲染1000个DOM。每个DOM都包含一个img标签。原生DOM本身就是一个非常复杂的对象,加上img标签后。渲染效果如下图所示:可以明显的看到白屏半天,因为在React中,没有做任何优化,直接渲染了这样一个包含1000张图片的dom节点,虽然React本身使用的是虚拟dom,但是,第一次渲染时,实际生成了1000个真实DOM。我们可以查看网页中真实的DOM情况,如下图:从上图可以看出,实际生成了1000个真实的DOM。一个真正的dom,进入页面后,需要渲染这1000个dom,所以白屏时间比较长。另外,在直接渲染1000个dom节点的页面触发滚动事件也会增加内存占用,如下图所示:另外,同时渲染多个dom节点也会导致以下问题:容易丢帧,因为Rendering很慢,所以无法维持浏览器的帧率。主观上会出现页面卡顿,网页失去响应,无法及时触发事件。以上效果均在PC端显示。针对特定的移动设备,没有优化直接渲染长列表带来的问题。长列表的渲染在移动端很多场景都会遇到,比如微博、动态等,对长列表进行合理的优化可以提升用户体验。2.长列表的虚拟列表优化原理长列表的优化原理很简单。基本原理可以用一句话概括:用一个数组保存所有列表元素的位置,只渲染可见区域的列表元素。当可见区域滚动时,根据滚动偏移大小和所有列表元素的位置,计算哪些元素应该在可见区域渲染。具体实现步骤如下:首先,确定长列表所在父元素的大小。父元素的大小决定了可见区域的宽度和高度。确定长列表中每个列表元素的宽度和高度。同时计算初始条件下的长度。列表的每个元素相对于父元素的位置,用一个数组保存所有列表元素的位置信息。第一次渲染时,只显示相对于父元素可视区域内的子列表元素。滚动时,父元素滚动偏移量,以重新计算应在视口内的子列表元素。这样可以保证不管怎么滚动,真正渲染出来的dom节点只是可见区域的列表元素。假设可见区域可以显示5个子列表元素,长列表一共有1000个元素,但任何时刻,实际渲染的dom节点只有5个。5.补充说明,这种情况下,父元素一般使用position:relative,子元素的定位一般使用:position:absolute或者sticky。优化虚拟列表后,1000个包含图片的dom也会显示出来,白屏时间会大大减少。具体效果如下图所示:对于没有优化的情况,优化后的虚拟列表渲染速度有明显提升。3.通过react-virtualized优化长列表社区中有很多React组件来实现虚拟列表。比较常用的是react-virtualized和react-tiny-virtual-list。前者更全面,后者更轻松。下面分别介绍这两个React组件库。一、react-virtualized介绍react-virtualized是一个优秀的实现虚拟列表的组件库。react-virtualized提供了一些实现虚拟列表、虚拟网格、虚拟表格等的基础组件,可以减少不必要的dom渲染。另外还提??供了几个高级组件,可以实现动态子元素高度,自动填充可见区域等。react-virtualized的基本组件包括:Grid:用于优化构建任意网格结构,通过在一个二维数组中,并渲染一个类似棋盘的结构。List:List是基于Grid实现的,但它是维度列表,不是网格。Table:Table也是基于Grid实现的。表格有一个固定的头部,可以垂直滚动。Masonry:它也可以水平或垂直滚动??。与Grid不同的是,每个元素都可以自定义Size,或者子元素的大小也可以是一个动态变化的Collection:类似于瀑布,也可以水平和垂直滚动。值得注意的是,这些基础组件都是从React中的PureComponent继承而来的,所以当状态发生变化时,只是进行浅层比较来决定是否重新渲染。除了这些基础组件,react-virtualized还提供了几个高级组件,如ArrowKeyStepper、AutoSizer、CellMeasurer、InfiniteLoader等,本文专门介绍常用的AutoSizer、CellMeasurer和InfiniteLoader。AutoSizer:在子元素的情况下,AutoSizer包含的子元素会根据父元素Resize的变化自动调整子元素可视区域的宽高,同时调整子元素的真实可视区域渲染的dom元素的数量。CellMeasurer:这个高阶组件可以动态改变子元素的高度,适用于事先不知道长列表中每个子元素高度的情况。InfiniteLoader:该高级组件用于Table或List的无限滚动,适用于滚动时异步请求等情况。2、react-virtualized基础组件的使用介绍下常用的基础组件Grid和List。(1)Grid的所有基础组件基本都是基于Grid的。Grid的一个简单示例如下:import{Grid}from'react-virtualized';constlist=[['Jonyyu','软件工程师','深圳','中国','广州'],['Jonyyu','软件工程师','深圳','中国','广州'],['Jonyyu','软件工程师','深圳','CHINA','广州'],['Jonyyu','软件工程师','深圳','CHINA','广州'],['Jonyyu','SoftwareEngineer','Shenzhen','CHINA','GUANGZHOU'],['Jonyyu','SoftwareEngineer','Shenzhen','CHINA','GUANGZHOU']];函数cellRenderer({columnIndex,key,rowIndex,style}){return(
