全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2024-07-10_性能飙升50%,react-virtualized-list如何优化大数据集滚动渲染

您的位置:首页 >> 新闻 >> 行业资讯

性能飙升50%,react-virtualized-list如何优化大数据集滚动渲染 关注公众号,“技术干货”及时!引言:在处理大规模数据集渲染时,前端性能常常面临巨大的挑战。本文将探讨 react-virtualized-list 库如何通过虚拟化技术和 「Intersection Observer API」,实现前端渲染性能飙升 「50%」 的突破,页面渲染速度提升「95%」!借助目录阅读,效果更佳。 事情的起因最近,公司监控系统出现了加载卡顿和白屏问题,需要一个能够处理大规模数据渲染的方案。由于核心需求是列表项数据需要动态更新和自动刷新,所以用到了 react-virtualized-list 库。 如果你正在寻找解决大数据集渲染瓶颈的方法,或是希望提升前端应用的响应速度,这篇文章将为你带来全新的启发与实用的解决方案。希望对你有所帮助、有所借鉴。大家有什么疑问或者建议,欢迎在评论区一起讨论! 什么是虚拟化?虚拟化技术,顾名思义,是一种通过仅渲染当前用户可见的数据项,而不是整个数据集,来优化性能的技术。这种技术在处理大量数据时尤为重要,因为它显著减少了 DOM 节点的数量,从而提高了性能。通过虚拟化,可以在用户滚动列表时动态加载和卸载元素,保持界面流畅。 下面是react-virtualized-list在虚拟化方面做的处理: 我们来看看真实的 DOM 情况! react-virtualized-list 简介react-virtualized-list 是一个专门用于显示大型数据集的高性能 React 组件库。它同时适用于 「PC 端」和「移动端」,通过虚拟化技术实现了延迟加载和无限滚动功能,尤其是非常适合需要高效渲染和加载大量数据的应用场景,如聊天记录、商品列表等。 此外,react-virtualized-list 库还提供了场景适用的效果展示和示例代码。 核心特性 ????「高性能」:仅渲染当前视口内的元素,显著减少 DOM 节点数量。「延迟加载」:动态加载数据,避免一次性加载大量数据带来的性能问题。「无限滚动」:支持无限滚动,用户可以持续滚动查看更多内容。「自定义渲染」:提供灵活的 API,允许开发者自定义列表项的渲染方式。「视口内刷新」:支持自动刷新视口内的内容,确保数据的实时性。「支持 TS 和 JS」:适用于 TypeScript 和 JavaScript 项目。安装可以通过 npm 或 yarn 轻松安装 react-virtualized-list: npminstallreact-virtualized-list #或者 yarnaddreact-virtualized-list 基本用法下面是一个简单的示例,展示了如何使用 react-virtualized-list 创建一个无限滚动的虚拟化列表: importReact,{useState,useEffect}from'react'; importVirtualizedListfrom'react-virtualized-list'; import'./style/common.css'; constInfiniteScrollList=()={ const[items,setItems]=useState([]); const[hasMore,setHasMore]=useState(true); constloadMoreItems=()={ //模拟API调用,延迟1秒加载新数据 setTimeout(()={ constnewItems=Array.from({length:20},(_,index)=({ id:items.length+index, text:`Item${items.length+index}` setItems(prevItems=[...prevItems,...newItems]); setHasMore(newItems.length0); },1000); useEffect(()={ loadMoreItems(); }, constrenderItem=(item)=div{item.text}/div; return( divclassName='content' VirtualizedList listData={items} renderItem={renderItem} containerHeight='450px' itemClassName='item-class' onLoadMore={loadMoreItems} hasMore={hasMore} loader={divLoading.../div} endMessage={divNomoreitems/div} / /div }; exportdefaultInfiniteScrollList; /*./style/common.css*/ .content{ width:350px; padding:16px; border:1pxsolid margin-top:10vh; } .item-class{ height:50px; border:1pxsolidblue; margin:0px010px; padding:10px; background-color:#f0f0f0; } 通过 onLoadMore 和 hasMore 属性实现无限滚动,在用户滚动到列表底部时自动加载更多数据。这种功能常见于滚动加载下页数据。 进阶用法1. 动态加载数据为了进一步提高性能,可以使用动态加载技术,只在需要时加载数据。以下是一个示例,展示了如何结合 react-virtualized-list 和动态数据加载: importReact,{useState,useEffect}from'react'; importVirtualizedListfrom'react-virtualized-list'; import'./style/common.css'; constfetchProductData=async(product)={ returnnewPromise((resolve)={ setTimeout(()={ resolve({description:`Descriptionfor${product.name}`,imageUrl:`https://via.placeholder.com/150?text=Product+${product.id}` },500); }; constfetchProducts=async(page)={ returnnewPromise((resolve)={ setTimeout(()={ constproducts=Array.from({length:10},(_,i)=({ id:page*10+i, name:`Product${page*10+i}` resolve(products); },500); }; constDynamicInfiniteList=()={ const[products,setProducts]=useState([]); const[hasMore,setHasMore]=useState(true); const[page,setPage]=useState(0); constloadMoreProducts=async()={ constnewProducts=awaitfetchProducts(page); setProducts(prevProducts=[...prevProducts,...newProducts]); setPage(prevPage=prevPage+1); if(newProducts.length10)setHasMore(false); useEffect(()={ loadMoreProducts(); }, return( divclassName='content' VirtualizedList listData={products} renderItem={(product,data)=( div h2{product.name}/h2 p{data?data.description:'Loading...'}/p {dataimgsrc={data.imageUrl}alt={product.name}/} /div )} itemClassName='item-class-dynamic' fetchItemData={fetchProductData} onLoadMore={loadMoreProducts} hasMore={hasMore} containerHeight='500px' loader='Loadingmoreproducts...' endMessage='Nomoreproducts' / /div }; exportdefaultDynamicInfiniteList; /*./style/common.css*/ .content{ width:350px; padding:16px; border:1pxsolid margin-top:10vh; } .item-class-dynamic{ height:300px; padding:20px; border-bottom:1pxsolid#eee; } 「注意」:在上面代码中,我们使用 onLoadMore 模拟商品列表的滚动加载,并在 VirtualizedList 组件的 fetchItemData 实现了商品详情的动态加载。这对于大数据集下,「后端无法一次性返回数据非常有利」! 2. 自定义渲染react-virtualized-list 还提供了自定义渲染功能,开发者可以根据具体需求定制列表项的渲染方式。以下是一个示例,展示了如何自定义列表项的样式和内容: importReactfrom'react'; importVirtualizedListfrom'react-virtualized-list'; constdata=Array.from({length:1000}).map((_,index)=({ title:`Item${index}`, index:index, description:`Thisisthedescriptionforitem${index}.` })); constListItem=({item,style})=( divstyle={{...style,padding:'10px',borderBottom:'1pxsolid#ccc'}} h3{item.title}/h3 p{item.description}/p /div ); constitemStyle={ height:'100px', border:'1pxsolidblue', margin:'0px010px', padding:'10px', backgroundColor:'#f0f0f0' }; constMyVirtualizedList=()=( divstyle={{width:'350px',padding:'16px',border:'1pxsolidred'}} VirtualizedList listData={data} itemStyle={itemStyle} renderItem={({index,style})=ListItemitem={data[index]}style={style}/} containerHeight='80vh' / /div ); exportdefaultMyVirtualizedList; 此外,react-virtualized-list 还提供了其他的用法场景和相关 API,详情请见使用文档。 实现原理(??核心重点)在构建大型 Web 应用时,经常会遇到需要展示大量数据的情况,比如电子商务平台的产品列表等。传统的渲染方式可能会面临性能问题,因为它们需要在页面上同时呈现大量 DOM 元素,导致页面加载缓慢、滚动卡顿等问题。 为了解决这个问题,我们可以使用虚拟化列表来优化渲染过程。而 react-virtualized-list 库的核心在于通过虚拟化技术优化渲染过程。其主要原理包括以下几点: 1. 可视区域监测:利用Intersection Observer API在虚拟化列表的实现中,一个关键步骤是监测可视区域内的元素。为了实现懒加载、滚动动画等需求,传统的方法是通过监听滚动事件并计算每个元素的位置来实现。需要获取「元素与视窗的交叉状态」,这通常使用「监听滚动事件 + 计算偏移量 + 判断逻辑」的方式实现,再配合防抖等优化,然而这种方式效率较低。 //获取需要监测可视性的元素 constelements=document.querySelectorAll('.target-element'); //监听滚动事件 window.addEventListener('scroll',()={ //计算每个元素的位置 elements.forEach(element={ constrect=element.getBoundingClientRect(); if( rect.top=0&& rect.left=0&& rect.bottom=(window.innerHeight||document.documentElement.clientHeight)&& rect.right=(window.innerWidth||document.documentElement.clientWidth) ){ //元素在可视区域内 //执行相应操作 console.log(`${element}isvisible.`); } }); 相比之下,我们可以利用现代浏览器提供的 Intersection Observer API 来更高效地监测元素的可见性变化。 //定义一个IntersectionObserver constobserver=newIntersectionObserver(entries={ entries.forEach(entry={ //如果元素可见 if(entry.isIntersecting){ //执行相应操作 console.log(`${entry.target}isvisible.`); } }); //获取需要监测可视性的元素 constelements=document.querySelectorAll('.target-element'); //监测每个元素 elements.forEach(element={ observer.observe(element); }); 这里封装了一个 React Hooks useIntersectionObserver,提供了Intersection Observer API 的能力。 「2. 仅渲染可见区域:优化性能」虚拟化列表的另一个关键优化是仅渲染可见区域内的元素,而不是渲染整个列表。这样做可以大大减少渲染所需的时间和资源,提高页面的性能表现。 importuseIntersectionObserverfrom'./useIntersectionObserver'; const[visibleItems,setVisibleItems]=useStateSetnumber(newSet()); consthandleVisibilityChange=useCallback((isVisible:boolean,entry:IntersectionObserverEntry)={ constindex=parseInt(entry.target.getAttribute('data-index')!,10); setVisibleItems(prev={ constnewVisibleItems=newSet(prev); if(isVisible){ newVisibleItems.add(index); }else{ newVisibleItems.delete(index); } returnnewVisibleItems; }, const{observe,unobserve}=useIntersectionObserver(containerRef.current,handleVisibilityChange,null,observerOptions); 3. 动态加载和卸载:保持内存使用最小化最后,虚拟化列表还可以通过动态加载和卸载元素来保持内存使用最小化。当用户滚动到可视区域时,新的元素被动态加载,而离开可视区域的元素则被卸载,从而减少页面的内存占用。 constvisibleRange=useMemo(()={ constsortedVisibleItems=[...visibleItems].sort((a,b)=a- constfirstVisible=sortedVisibleItems[0]||0; constlastVisible=sortedVisibleItems[sortedVisibleItems.length-1]||0; //设置缓存区 return[Math.max(0,firstVisible-BUFFER_SIZE),Math.min(listData.length-1,lastVisible+BUFFER_SIZE)]; },[visibleItems,listData.length]); constrenderItems=()={ returnlistData.length?listData.map((item,index)={ if(index=visibleRange[0]index=visibleRange[1]){ return( div className={itemClassName||undefined} style={itemContainerStyle} ref={node=handleRef(node,index)} key={index} data-index={index} VirtualizedListItem item={listData[index]} isVisible={visibleItems.has(index)} refreshOnVisible={refreshOnVisible} fetchItemData={fetchItemData} itemLoader={itemLoader} {renderItem} /VirtualizedListItem /div } returnnull; }):( emptyListMessage?emptyListMessage:null 当元素进入视口时,我们加载它;当元素离开视口时,我们卸载它。这样就可以保持页面上始终只有视口内的内容被渲染,从而提高页面的性能和响应速度。 ?除此之外,通过使用 useMemo 计算当前可见的列表项范围 (visibleRange),以及设置一个缓冲区 (BUFFER_SIZE);使用useMemo 和 useCallback 用于性能优化的 Hook。它们帮助避免不必要的计算和重新渲染。 ?性能对比(??性能飙升 50%)下面我们就来看下,传统滚动 Scroll 监听和 Intersection Observer API 的性能对比数据(假设在相同环境和数据集下测试): 方法初始渲染时间滚动性能内存使用传统滚动监听300ms低高Intersection Observer API150ms高低「初始渲染时间」:使用 Intersection Observer API 的初始渲染时间较短,因为只渲染可见区域。「滚动性能」:传统滚动监听由于频繁的滚动事件触发和位置计算,滚动性能较低;Intersection Observer API 的滚动性能较高,因为它利用了浏览器的优化机制。「内存使用」:Intersection Observer API 由于仅加载和渲染可见元素,内存使用更低。性能测试代码分析以下是一个示例,展示了如何使用 console.time 和 console.timeEnd 来测量性能: //测量传统滚动监听的性能 console.time('Scroll'); window.addEventListener('scroll',()={ //模拟计算每个元素的位置 constelements=document.querySelectorAll('.target-element'); elements.forEach(element={ constrect=element.getBoundingClientRect(); if(rect.top=0rect.bottom=window.innerHeight){ //模拟渲染逻辑 } }); console.timeEnd('Scroll'); //测量IntersectionObserverAPI的性能 console.time('IntersectionObserver'); constobserver=newIntersectionObserver(entries={ entries.forEach(entry={ if(entry.isIntersecting){ //模拟渲染逻辑 } }); constelements=document.querySelectorAll('.target-element'); elements.forEach(element=observer.observe(element)); console.timeEnd('IntersectionObserver'); ?「注意」:传统滚动监听方法还会涉及大量计算,这里仅简单测量了监听性能的统计部分。 ?传统的滚动监听方式通过监听 scroll 事件,在每次滚动时计算每个目标元素的位置,并判断其是否在视窗内。这部分代码的执行会阻塞主线程,尤其在滚动频繁的情况下可能导致性能问题,因为需要不断重新计算元素位置。 相比之下,Intersection Observer API 更高效。它可以检测元素是否可见,并在元素进入或退出视窗时触发回调函数,从而实现需要的功能。 性能总结在性能方面,传统实现方法通常需要通过监听滚动(scroll)事件来计算元素位置。这种方法存在以下问题: 「性能消耗大」:频繁监听滚动事件会导致性能消耗增加,尤其是在大型数据集的情况下。「计算复杂度高」:需要手动计算每个列表项与视口的交叉情况,逻辑复杂且容易出错。需要花费大量时间和精力来优化和调试这些计算逻辑。相比之下,Intersection Observer API 的性能更优,具有以下优点: 「性能开销低」:Intersection Observer API 利用浏览器的内部优化机制,减少了不必要的计算和事件触发,从而提高了性能。相比之下,传统的 scroll 事件监听方式由于密集触发,可能会导致较大的性能问题。「多元素监测」:Intersection Observer API 允许同时监测多个元素的交叉状态,而不需要为每个元素都绑定事件监听器。这使得在处理复杂布局和交互时更加高效。「异步执行」:当元素进入或离开交叉状态时,Intersection Observer 会异步执行回调函数,不会阻塞主线程。这有助于保持页面的响应性和流畅性。「应用场景广泛」:Intersection Observer API 可以应用于多种场景,如懒加载、无限滚动、广告展示与统计、页面元素动画等。这些应用场景通常需要高效地处理元素与视口之间的交互。综上所述,Intersection Observer API 在处理大型数据集和复杂交互时,相比传统的 scroll 事件监听方式,提供了更高的性能和更灵活的解决方案。 项目成果展示(??渲染速度提升95%)下面我们看下优化后的性能,展示实际改进的用户体验和加载时间。 首先从视觉感官上看,几乎是一瞬间图表就加载了出来。我们接着再来看看接口Network与数据对比! 为了清楚地展示优化前后页面加载速度的提升,我们可以将相关数据整理成一个表格形式,如下所示: 优化指标优化前优化后加载速度提升总耗时15000 毫秒(15秒)750 毫秒提速了95%这个表格展示了优化措施的显著效果,从中可以看出,经过优化后,整体加载时间也从15000毫秒大幅减少至750毫秒,加载速度提高了95%。 总结通过使用 react-virtualized-list 库,监控系统项目前端渲染性能得到了显著提升。统计结果显示:「页面加载速度提高了 95%,用户体验得到了明显改善」。如果你也在处理大数据集的渲染问题,不妨试试这个库。 希望本文能对你有所帮助,有所借鉴!大家有什么疑问或者建议,欢迎在评论区一起讨论。 参考资料Intersection Observer APIreact-virtualized-list详解 Intersection Observer API ( 交叉观察器 )关注公众号,“技术干货”及时! 阅读原文

上一篇:2022-10-14_手握和乐怡,与沿途风景的微醺时刻干杯 下一篇:2023-02-04_曾因不知NP困难怕被导师拒绝,滕尚华游戏中找到人生经验,两次获哥德尔奖

TAG标签:

18
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价