长列表数据对象创建耗时过长导致UI卡顿

长列表数据刷新创建数据对象耗时过长,导致刷新数据是滑动卡顿。

HarmonyOS
2024-09-29 13:16:40
浏览
收藏 0
回答 2
回答 2
按赞同
/
按时间
鱼弦CTO
1

在处理长列表数据时,数据对象的创建耗时过长确实会导致 UI 卡顿。为了解决这个问题,可以采用以下几种优化策略:

  1. 懒加载和分页:按需加载数据,避免一次性加载所有数据。
  2. 虚拟滚动(Virtual Scrolling):只渲染可视区域内的列表项。
  3. 使用 Web Workers:将数据处理任务放到 Web Worker 中,避免阻塞主线程。
  4. 性能优化技术:如使用​​useMemo​​、​​useCallback​​ 等 React 性能优化手段。

### 示例代码

下面是一个示例代码,展示了如何使用虚拟滚动和懒加载来优化长列表的数据加载与渲染。

#### 1. 使用虚拟滚动的长列表组件

首先,安装 ​​react-window​​ 库,这是一个轻量级的虚拟滚动库:

npm install react-window
  • 1.

接下来,创建一个使用虚拟滚动的长列表组件:

import React, { useState, useEffect } from 'react';
import { FixedSizeList as List } from 'react-window';

const generateData = (numItems: number) => {
  return Array.from({ length: numItems }, (_, index) => ({
    id: index,
    text: `Item ${index}`
  }));
};

function VirtualizedList() {
  const [data, setData] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // 模拟数据加载
    setTimeout(() => {
      const newData = generateData(1000);
      setData(newData);
      setIsLoading(false);
    }, 1000);
  }, []);

  const Row = ({ index, style }) => (
    <div style={style}>
      {data[index]?.text || "Loading..."}
    </div>
  );

  if (isLoading) {
    return <div>Loading...</div>;
  }

  return (
    <List
      height={400}
      itemCount={data.length}
      itemSize={35}
      width="100%"
    >
      {Row}
    </List>
  );
}

export default VirtualizedList;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.

#### 2. 使用 Web Worker 进行数据处理

为了避免主线程被大规模数据处理任务阻塞,可以使用 Web Worker 进行数据处理:

worker.js

onmessage = function (e) {
  const numItems = e.data;
  const data = Array.from({ length: numItems }, (_, index) => ({
    id: index,
    text: `Item ${index}`
  }));
  postMessage(data);
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

VirtualizedList.tsx

import React, { useState, useEffect } from 'react';
import { FixedSizeList as List } from 'react-window';

function VirtualizedList() {
  const [data, setData] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const worker = new Worker(new URL('./worker.js', import.meta.url));
    worker.postMessage(1000); // 发送要生成的数据条数
    worker.onmessage = (e) => {
      setData(e.data);
      setIsLoading(false);
    };

    return () => worker.terminate();
  }, []);

  const Row = ({ index, style }) => (
    <div style={style}>
      {data[index]?.text || "Loading..."}
    </div>
  );

  if (isLoading) {
    return <div>Loading...</div>;
  }

  return (
    <List
      height={400}
      itemCount={data.length}
      itemSize={35}
      width="100%"
    >
      {Row}
    </List>
  );
}

export default VirtualizedList;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.

### 解释

  1. 虚拟滚动
  • 使用​​react-window​​ 库中的​​FixedSizeList​​ 组件,实现了虚拟滚动,只渲染可视区域内的列表项,从而极大地提高了渲染性能。
  1. Web Worker
  • 将大规模数据处理任务移到 Web Worker 中执行,避免了阻塞主线程,从而保持了 UI 的流畅性。
  1. 懒加载
  • 在​​useEffect​​ 中模拟数据加载,通过​​setTimeout​​ 延迟加载数据,并在加载完成后更新状态。

通过这些优化策略,可以有效缓解长列表数据对象创建耗时过长导致的 UI 卡顿问题。如果有任何进一步的问题或需求,请随时提问!

分享
微博
QQ
微信
回复
2024-09-29 14:06:09
FengTianYa

参考:

import { DataSource } from '../DataSource';  
import { Item } from './Item';  
  
@Entry  
@Component  
struct Index {  
  @State message: string = 'Hello World';  
  dataSource: DataSource = new DataSource([])  
  datalist:Array<string> = new Array(50)  
  
  aboutToAppear(): void {  
    let time = new Date().getTime()  
    let cost = 'new 5000 Class50 cost : ' + (new Date().getTime() - time)  
    this.datalist.fill(cost)  
    this.dataSource.addData(0,this.datalist)  
  }  
  
  
  build() {  
    Row() {  
      List() {  
        LazyForEach(this.dataSource, (str: string, index: number) => {  
          Item({ str: str })  
        }, (str: string, index: number) => str + '-' + index)  
      }.onReachEnd(()=>{  
        let time = new Date().getTime()  
        for (let index = 0; index < 50; index++) {  
          new Class50()  
        }  
        let cost = 'new 5000 Class50 cost : ' + (new Date().getTime() - time)  
        this.dataSource.addData(this.datalist.length,new Array<string>(50).fill(cost))  
      })  
    }  
    .height('100%')  
  }  
}  
@Observed  
class Class50 extends Class40{  
  param40: string = ''  
  param41: string = ''  
  param42: string = ''  
  param43: string = ''  
  param44: string = ''  
  param45: string = ''  
  param46: string = ''  
  param47: string = ''  
  param48: string = ''  
  param49: string = ''  
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
分享
微博
QQ
微信
回复
2024-09-29 17:52:38


相关问题
鸿蒙开发中UI界面怎么解决?
253浏览 • 0回复 待解决
鸿蒙优化,如何检测线上
347浏览 • 0回复 待解决
HarmonyOS 手机系统升级后ui变得
1015浏览 • 1回复 待解决
HarmonyOS LazyForEach多层级数据性能
1063浏览 • 1回复 待解决
HarmonyOS 页面滑动
809浏览 • 1回复 待解决
ListContainer加载大量数据白屏并且UI
6134浏览 • 1回复 待解决
HarmonyOS 横竖屏翻转
747浏览 • 1回复 待解决
优化还有哪些方案
311浏览 • 0回复 待解决
HarmonyOS List嵌套waterflow滑动
979浏览 • 1回复 待解决
HarmonyOS 页面嵌套滑动时
742浏览 • 1回复 待解决