长列表数据对象创建耗时过长导致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

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

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;

#### 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);
};

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. 虚拟滚动
  • 使用​​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 = ''  
}
分享
微博
QQ
微信
回复
2024-09-29 17:52:38
相关问题
HarmonyOS List嵌套waterflow滑动
186浏览 • 1回复 待解决
ListContainer加载大量数据白屏并且UI
5382浏览 • 1回复 待解决
Web嵌套滑动怎么办?
158浏览 • 1回复 待解决
关于启动慢问题首帧分析
303浏览 • 1回复 待解决
"NAPI通信耗时长"导致丢帧分析
632浏览 • 1回复 待解决
自定义组件,怎么办啊?
237浏览 • 1回复 待解决
修改ForEach使用的数据对象UI不刷新
1403浏览 • 1回复 待解决
openharmony napi 异步耗时阻塞js的ui刷新
5401浏览 • 1回复 已解决
HarmonyOS 本地加载数据太卡
139浏览 • 1回复 待解决