在这里插入图片描述

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

📋 前言

@shopify/flash-list 是 Shopify 开发的高性能列表组件,专为解决 React Native 中大量数据渲染的性能问题而设计。与传统 FlatList 相比,FlashList 采用全新的渲染机制,通过虚拟化渲染、智能预加载、内存回收等技术,能够轻松处理数千甚至上万个列表项的流畅滚动,特别适合商品列表、聊天记录、社交媒体信息流等大数据量场景。该库支持 Android、iOS 和 HarmonyOS 三端,为跨平台应用提供了统一的高性能列表解决方案。

🎯 库简介

基本信息
  • 库名称: @shopify/flash-list

  • 版本信息:

    • 1.6.4: 支持 RN 0.72 版本(@react-native-ohos/flash-list)
    • 1.8.3: 支持 RN 0.77 版本(@react-native-ohos/flash-list)
  • 官方仓库: https://github.com/Shopify/flash-list

  • 主要功能:

    • 虚拟化渲染:仅渲染可见区域的列表项,大幅减少内存占用
    • 智能预加载:根据滚动方向和速度智能预渲染列表项
    • 自动内存回收:自动回收不可见区域的内存
    • 多列布局:支持网格布局和瀑布流布局
    • 横向滚动:支持横向列表布局
    • 自定义组件:支持自定义 CellRendererComponent
    • 高度自适应:支持不同高度的列表项
    • 性能监控:提供性能监控和调试工具
  • 技术特点: 基于 React Native 的 View 和 ScrollView 实现,无需原生代码

  • 兼容性验证: 该第三方库支持直接从 npm 下载,完整支持 HarmonyOS 平台

为什么需要这个库?
  • 性能优异: 采用虚拟化渲染技术,能够处理数千个列表项的流畅滚动
  • 内存优化: 自动回收不可见区域的内存,大幅降低内存占用
  • 易于使用: API 设计简洁明了,与 FlatList API 高度兼容
  • 功能全面: 支持多列布局、横向滚动、自定义组件等高级功能
  • 跨平台: 支持 Android、iOS、HarmonyOS 三端,统一的 API
  • 社区活跃: Shopify 官方维护,持续更新和优化
  • 鸿蒙支持: 完整支持 HarmonyOS 平台,实现真正的跨平台

📦 安装步骤

1. 使用 npm 安装
npm install @react-native-ohos/flash-list@1.6.4-rc.1
2. 验证安装

安装完成后,检查 package.json 文件,应该能看到新增的依赖:

{
  "dependencies": {
    "@react-native-ohos/flash-list": "^1.6.4-rc.1",
    // ... 其他依赖
  }
}

🔧 HarmonyOS 平台配置 ⭐

1. 配置 overrides(必需步骤)⭐⭐⭐

[!WARNING] 必须在 harmony 工程根目录的 oh-package.json5 中添加 overrides 字段!

打开 harmony/oh-package.json5,添加:

{
  ...
  "overrides": {
    "@rnoh/react-native-openharmony": "./react_native_openharmony"
  }
}
2. 引入原生端代码

目前有两种方法:

方法一:通过 har 包引入(推荐)

[!TIP] har 包位于三方库安装路径的 harmony 文件夹下。

打开 harmony/entry/oh-package.json5,添加以下依赖:

"dependencies": {
    "@rnoh/react-native-openharmony": "file:../react_native_openharmony",
    "@react-native-ohos/flash-list": "file:../../node_modules/@react-native-ohos/flash-list/harmony/flash_list.har"
}

点击右上角的 sync 按钮

或者在终端执行:

cd harmony/entry
ohpm install
方法二:直接链接源码

[!TIP] 如需使用直接链接源码,请参考直接链接源码说明

步骤 1: 把 <RN工程>/node_modules/@react-native-ohos/flash-list/harmony 目录下的源码 flash_list 复制到 harmony 工程根目录下。

步骤 2: 在 harmony 工程根目录的 build-profile.json5 添加以下模块:

modules: [
  ...
  {
    name: 'flash_list',
    srcPath: './flash_list',
  }
]

步骤 3: 打开 flash_list/oh-package.json5,修改 @rnoh/react-native-openharmony 和项目的版本一致。

步骤 4: 打开 harmony/entry/oh-package.json5,添加以下依赖:

"dependencies": {
  "@rnoh/react-native-openharmony": "0.72.90",
  "@react-native-ohos/flash-list": "file:../flash_list"
}

步骤 5: 点击 DevEco Studio 右上角的 sync 按钮

3. 配置 CMakeLists 和引入 FlashListPackage

打开 harmony/entry/src/main/cpp/CMakeLists.txt,添加:

project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# RNOH_BEGIN: manual_package_linking_1
add_subdirectory("../../../../sample_package/src/main/cpp" ./sample-package)
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/flash-list/src/main/cpp" ./flash-list)
# RNOH_END: manual_package_linking_1

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# RNOH_BEGIN: manual_package_linking_2
target_link_libraries(rnoh_app PUBLIC rnoh_sample_package)
+ target_link_libraries(rnoh_app PUBLIC rnoh_flash_list)
# RNOH_END: manual_package_linking_2

打开 harmony/entry/src/main/cpp/PackageProvider.cpp,添加:

#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
#include "SamplePackage.h"
+ #include "FlashListPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        std::make_shared<SamplePackage>(ctx),
+       std::make_shared<FlashListPackage>(ctx)
    };
}
4. 在 ArkTs 侧引入 FlashListPackage

打开 harmony/entry/src/main/ets/RNPackagesFactory.ts,添加:

  ...
+ import { FlashListPackage } from '@react-native-ohos/flash-list/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new SamplePackage(ctx),
+   new FlashListPackage(ctx),
  ];
}
5. 配置 hvigor-config.json5(重要)

[!TIP] 引入原生代码之前请确认IDE版本,5.0.3.810及其之后的版本需要在harmony工程中的hvigor-config.json5文件中新增如下配置以解决路径过长导致的编译报错问题

打开 harmony/hvigor-config.json5,添加:

{
  "properties": {
    "ohos.nativeResolver": false
  },
  "module": {
    // ... 其他配置
  }
}
6. 运行

点击右上角的 sync 按钮

或者在终端执行:

cd harmony/entry
ohpm install

然后编译、运行即可。

💻 完整代码示例

下面是一个完整的示例,展示了如何使用 FlashList 构建实用的商品列表应用,包含多种展示模式和交互效果:

import React, { useState, useRef, memo, useCallback } from 'react';
import {
  View,
  StyleSheet,
  Text,
  Image,
  TouchableOpacity,
  SafeAreaView,
  ScrollView,
  ActivityIndicator,
  StatusBar,
  Dimensions,
} from 'react-native';
import { FlashList } from '@shopify/flash-list';

const { width } = Dimensions.get('window');

// 商品数据接口
interface Product {
  id: number;
  name: string;
  price: number;
  image: string;
  category: string;
  rating: number;
  reviews: number;
  sold: number;
  discount: number;
}

// 生成商品数据
const generateProducts = (count: number): Product[] => {
  const categories = ['电子产品', '服装鞋包', '家居用品', '食品生鲜', '美妆个护'];
  const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD'];
  
  return Array.from({ length: count }, (_, i) => ({
    id: i,
    name: `商品 ${i + 1}`,
    price: Math.floor(Math.random() * 1000) + 50,
    image: `https://via.placeholder.com/200?text=Product${i + 1}`,
    category: categories[i % categories.length],
    rating: parseFloat((Math.random() * 2 + 3).toFixed(1)),
    reviews: Math.floor(Math.random() * 1000),
    sold: Math.floor(Math.random() * 10000),
    discount: Math.random() > 0.7 ? Math.floor(Math.random() * 30) : 0,
  }));
};

// 商品卡片组件(使用 memo 优化性能)
const ProductCard = memo(({ item, onPress }: { item: Product; onPress: (item: Product) => void }) => {
  return (
    <TouchableOpacity style={styles.productCard} onPress={() => onPress(item)} activeOpacity={0.7}>
      <View style={styles.imageContainer}>
        <Image source={{ uri: item.image }} style={styles.productImage} />
        {item.discount > 0 && (
          <View style={styles.discountBadge}>
            <Text style={styles.discountText}>-{item.discount}%</Text>
          </View>
        )}
      </View>
      <View style={styles.productInfo}>
        <Text style={styles.categoryText}>{item.category}</Text>
        <Text style={styles.productName} numberOfLines={2}>{item.name}</Text>
        <View style={styles.ratingContainer}>
          <Text style={styles.rating}>{item.rating.toFixed(1)}</Text>
          <Text style={styles.reviews}>({item.reviews}评价)</Text>
        </View>
        <View style={styles.priceContainer}>
          {item.discount > 0 ? (
            <>
              <Text style={styles.originalPrice}>¥{Math.floor(item.price / (1 - item.discount / 100))}</Text>
              <Text style={styles.currentPrice}>¥{item.price}</Text>
            </>
          ) : (
            <Text style={styles.currentPrice}>¥{item.price}</Text>
          )}
        </View>
        <Text style={styles.soldText}>已售 {item.sold}</Text>
      </View>
    </TouchableOpacity>
  );
});

ProductCard.displayName = 'ProductCard';

// 列表头部组件
const ListHeader = memo(() => {
  return (
    <View style={styles.headerContainer}>
      <Text style={styles.headerTitle}>热门推荐</Text>
      <View style={styles.filterContainer}>
        <TouchableOpacity style={[styles.filterButton, styles.activeFilter]}>
          <Text style={styles.filterButtonText}>综合</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.filterButton}>
          <Text style={styles.filterButtonText}>销量</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.filterButton}>
          <Text style={styles.filterButtonText}>价格</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
});

ListHeader.displayName = 'ListHeader';

// 列表底部组件
const ListFooter = memo(({ isLoading }: { isLoading: boolean }) => {
  return (
    <View style={styles.footerContainer}>
      {isLoading ? (
        <View style={styles.loadingContainer}>
          <ActivityIndicator size="large" color="#409EFF" />
          <Text style={styles.loadingText}>加载中...</Text>
        </View>
      ) : (
        <Text style={styles.footerText}>没有更多商品了</Text>
      )}
    </View>
  );
});

ListFooter.displayName = 'ListFooter';

// 列表项分隔组件
const ItemSeparator = memo(() => {
  return <View style={styles.separator} />;
});

ItemSeparator.displayName = 'ItemSeparator';

// 主应用组件
const FlashListDemo = () => {
  const [products, setProducts] = useState<Product[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  const [viewMode, setViewMode] = useState<'list' | 'grid'>('grid');
  const listRef = useRef<FlashList<Product>>(null);

  // 加载商品数据
  const loadProducts = useCallback(() => {
    setIsLoading(true);
    // 模拟网络请求
    setTimeout(() => {
      const newProducts = generateProducts(100);
      setProducts(newProducts);
      setIsLoading(false);
    }, 500);
  }, []);

  // 加载更多
  const loadMore = useCallback(() => {
    if (isLoading) return;
    setIsLoading(true);
    setTimeout(() => {
      const newProducts = generateProducts(20);
      setProducts(prev => [...prev, ...newProducts]);
      setIsLoading(false);
    }, 1000);
  }, [isLoading]);

  // 商品点击事件
  const handleProductPress = useCallback((item: Product) => {
    console.log('点击商品:', item.name);
    // 这里可以跳转到商品详情页
  }, []);

  // 切换视图模式
  const toggleViewMode = useCallback(() => {
    setViewMode(prev => prev === 'list' ? 'grid' : 'list');
  }, []);

  // 刷新列表
  const handleRefresh = useCallback(() => {
    loadProducts();
  }, [loadProducts]);

  // 初始化加载数据
  React.useEffect(() => {
    loadProducts();
  }, [loadProducts]);

  return (
    <SafeAreaView style={styles.container}>
      <StatusBar barStyle="dark-content" backgroundColor="#ffffff" />
    
      {/* 顶部导航栏 */}
      <View style={styles.navbar}>
        <Text style={styles.navbarTitle}>商城首页</Text>
        <View style={styles.navbarActions}>
                <TouchableOpacity style={styles.navbarIcon} onPress={() => console.log('搜索')}>
                  <Text style={styles.iconText}>🔍</Text>
                </TouchableOpacity>
                <TouchableOpacity style={styles.navbarIcon} onPress={() => console.log('购物车')}>
                  <Text style={styles.iconText}>🛒</Text>
                </TouchableOpacity>
              </View>      </View>

      {/* 搜索栏 */}
      <View style={styles.searchContainer}>
        <View style={styles.searchBar}>
          <Text style={styles.searchIcon}>🔍</Text>
          <Text style={styles.searchPlaceholder}>搜索商品</Text>
        </View>
      </View>

      {/* 内容区域 */}
      <FlashList
        data={products}
        renderItem={({ item }) => (
          <ProductCard item={item} onPress={handleProductPress} />
        )}
        keyExtractor={(item) => item.id.toString()}
        estimatedItemSize={viewMode === 'grid' ? 280 : 120}
        numColumns={viewMode === 'grid' ? 2 : 1}
        contentContainerStyle={styles.listContent}
        ListHeaderComponent={ListHeader}
        ListFooterComponent={() => <ListFooter isLoading={isLoading} />}
        ItemSeparatorComponent={viewMode === 'list' ? ItemSeparator : null}
        onEndReached={loadMore}
        onEndReachedThreshold={0.5}
        onViewableItemsChanged={useCallback((info: any) => {
          console.log('可见商品数量:', info.viewableItems.length);
        }, [])}
        viewabilityConfig={{
          minimumViewTime: 300,
          viewAreaCoveragePercentThreshold: 10,
        }}
      />

      {/* 底部切换按钮 */}
      <View style={styles.bottomActions}>
        <TouchableOpacity style={styles.actionButton} onPress={toggleViewMode}>
          <Text style={styles.actionButtonText}>
            {viewMode === 'grid' ? '📋 列表视图' : '🔲 网格视图'}
          </Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.refreshButton} onPress={handleRefresh}>
          <Text style={styles.refreshButtonText}>🔄 刷新</Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#F5F7FA',
  },
  navbar: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    backgroundColor: '#FFFFFF',
    paddingHorizontal: 16,
    paddingVertical: 12,
    borderBottomWidth: 1,
    borderBottomColor: '#EBEEF5',
  },
  navbarTitle: {
    fontSize: 20,
    fontWeight: '700',
    color: '#303133',
  },
  navbarActions: {
    flexDirection: 'row',
  },
  navbarIcon: {
    width: 36,
    height: 36,
    justifyContent: 'center',
    alignItems: 'center',
    marginLeft: 12,
  },
  iconText: {
    fontSize: 20,
  },
  searchContainer: {
    backgroundColor: '#FFFFFF',
    paddingHorizontal: 16,
    paddingVertical: 12,
    borderBottomWidth: 1,
    borderBottomColor: '#EBEEF5',
  },
  searchBar: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#F5F7FA',
    borderRadius: 8,
    paddingHorizontal: 12,
    paddingVertical: 10,
  },
  searchIcon: {
    fontSize: 16,
    marginRight: 8,
  },
  searchPlaceholder: {
    fontSize: 14,
    color: '#909399',
  },
  listContent: {
    padding: 12,
  },
  headerContainer: {
    marginBottom: 16,
  },
  headerTitle: {
    fontSize: 18,
    fontWeight: '700',
    color: '#303133',
    marginBottom: 12,
  },
  filterContainer: {
    flexDirection: 'row',
  },
  filterButton: {
    paddingHorizontal: 16,
    paddingVertical: 8,
    backgroundColor: '#FFFFFF',
    borderRadius: 16,
    borderWidth: 1,
    borderColor: '#DCDFE6',
    marginRight: 8,
  },
  activeFilter: {
    backgroundColor: '#409EFF',
    borderColor: '#409EFF',
  },
  filterButtonText: {
    fontSize: 14,
    color: '#606266',
  },
  productCard: {
    backgroundColor: '#FFFFFF',
    borderRadius: 12,
    marginBottom: 12,
    overflow: 'hidden',
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  imageContainer: {
    position: 'relative',
    height: 150,
  },
  productImage: {
    width: '100%',
    height: '100%',
    resizeMode: 'cover',
  },
  discountBadge: {
    position: 'absolute',
    top: 8,
    left: 8,
    backgroundColor: '#F56C6C',
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 4,
  },
  discountText: {
    color: '#FFFFFF',
    fontSize: 12,
    fontWeight: '600',
  },
  productInfo: {
    padding: 12,
  },
  categoryText: {
    fontSize: 12,
    color: '#909399',
    marginBottom: 4,
  },
  productName: {
    fontSize: 14,
    fontWeight: '600',
    color: '#303133',
    marginBottom: 6,
    lineHeight: 20,
  },
  ratingContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 6,
  },
  rating: {
    fontSize: 12,
    color: '#E6A23C',
    marginRight: 4,
  },
  reviews: {
    fontSize: 12,
    color: '#909399',
  },
  priceContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 4,
  },
  originalPrice: {
    fontSize: 12,
    color: '#909399',
    textDecorationLine: 'line-through',
    marginRight: 8,
  },
  currentPrice: {
    fontSize: 18,
    fontWeight: '700',
    color: '#F56C6C',
  },
  soldText: {
    fontSize: 12,
    color: '#909399',
  },
  separator: {
    height: 12,
  },
  footerContainer: {
    paddingVertical: 20,
    alignItems: 'center',
  },
  loadingContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  loadingText: {
    fontSize: 14,
    color: '#909399',
    marginLeft: 8,
  },
  footerText: {
    fontSize: 14,
    color: '#909399',
  },
  bottomActions: {
    flexDirection: 'row',
    backgroundColor: '#FFFFFF',
    borderTopWidth: 1,
    borderTopColor: '#EBEEF5',
    padding: 12,
    paddingHorizontal: 16,
  },
  actionButton: {
    flex: 1,
    backgroundColor: '#409EFF',
    borderRadius: 8,
    paddingVertical: 12,
    alignItems: 'center',
    marginRight: 12,
  },
  actionButtonText: {
    color: '#FFFFFF',
    fontSize: 16,
    fontWeight: '600',
  },
  refreshButton: {
    backgroundColor: '#67C23A',
    borderRadius: 8,
    paddingHorizontal: 24,
    paddingVertical: 12,
    alignItems: 'center',
  },
  refreshButtonText: {
    color: '#FFFFFF',
    fontSize: 16,
    fontWeight: '600',
  },
});

export default FlashListDemo;

🎨 实际应用场景

完整示例代码已展示了以下实际应用场景:

  • 电商商品列表: 展示商品图片、价格、折扣、销量等信息
  • 多种视图模式: 支持网格视图和列表视图切换
  • 上拉加载更多: 自动检测滚动到底部,加载更多数据
  • 下拉刷新: 提供刷新功能,重新加载数据
  • 商品筛选: 支持按综合、销量、价格等条件筛选
  • 性能优化: 使用 React.memo 优化组件渲染性能
  • 滚动监控: 实时监控可见商品数量

⚠️ 注意事项与最佳实践

1. estimatedItemSize 配置(重要)

[!WARNING] estimatedItemSize 是 FlashList 最重要的性能优化参数,必须设置!

// 正确:设置合理的预估大小
<FlashList estimatedItemSize={280} />

// 错误:不设置或设置不准确的值
<FlashList /> // 会导致首次渲染延迟

设置建议

  • 网格视图:设置为单个商品卡片的预估高度
  • 列表视图:设置为单个列表项的预估高度
  • 动态高度:使用 overrideItemLayout 提供精确的高度
2. drawDistance 配置

使用 drawDistance 控制预渲染的绘制距离,平衡性能和流畅度:

// 推荐配置
drawDistance={250}  // 预渲染 250 像素

// 大数据量场景
drawDistance={500} // 预渲染 500 像素

// 小数据量场景
drawDistance={100} // 预渲染 100 像素
3. React.memo 性能优化

对所有列表项组件使用 memo 优化,避免不必要的重新渲染:

const ProductCard = memo(({ item, onPress }) => {
  // 组件实现
});

ProductCard.displayName = 'ProductCard';
4. keyExtractor 配置

确保 keyExtractor 返回唯一的键值:

// 正确:使用唯一 ID
keyExtractor={(item) => item.id.toString()}

// 错误:使用索引(可能导致性能问题)
keyExtractor={(item, index) => index.toString()}
5. numColumns 配置

多列布局时,确保所有商品卡片高度一致:

// 网格布局
<FlashList
  numColumns={2}
  estimatedItemSize={280}
/>

// 列表布局
<FlashList
  numColumns={1}
  estimatedItemSize={120}
/>
6. removeClippedSubviews 使用

在鸿蒙端,removeClippedSubviews 可以有效减少内存占用:

<FlashList
  removeClippedSubviews={true}
/>
7. onEndReached 配置

合理配置上拉加载更多的阈值:

<FlashList
  onEndReached={loadMore}
  onEndReachedThreshold={0.5} // 距离底部 50% 时触发
/>
8. viewabilityConfig 配置

使用 viewabilityConfig 监控商品可见性:

<FlashList
  onViewableItemsChanged={handleViewableItemsChanged}
  viewabilityConfig={{
    minimumViewTime: 300,
    viewAreaCoveragePercentThreshold: 10,
  }}
/>
9. 版本兼容性

根据 RN 版本选择对应的库版本:

RN 版本 @react-native-ohos/flash-list
0.72 1.6.4
0.77 1.8.3

📊 对比:FlatList vs FlashList

特性 FlatList FlashList
虚拟化渲染 ✅ 支持 ✅ 支持(更优)
预加载机制 ⚠️ 简单 ✅ 智能预加载
内存回收 ⚠️ 基础 ✅ 自动回收
多列布局 ✅ 支持 ✅ 支持(更优)
性能表现 ⚠️ 中等 ✅ 优秀(2-5倍提升)
API 兼容性 ✅ 标准 ✅ 高度兼容
学习成本 ✅ 低 ✅ 低
鸿蒙支持 ✅ 支持 ✅ 支持(性能更优)

📝 总结

通过集成 @shopify/flash-list,我们为项目添加了强大的高性能列表渲染能力。这个库采用虚拟化渲染技术,能够轻松处理数千个列表项的流畅滚动,特别适合电商商品列表、社交媒体信息流、聊天记录等大数据量场景。

关键要点回顾
  • 安装依赖: npm install @react-native-ohos/flash-list
  • 配置 overrides: 在 oh-package.json5 中添加 overrides 字段
  • 配置平台: 通过 har 包或直接链接源码,配置 CMakeLists.txt 和 PackageProvider.cpp
  • 配置 hvigor: 在 hvigor-config.json5 中添加 nativeResolver 配置
  • 集成代码: 使用 FlashList 组件提供的各种 API
  • 性能优化: 合理配置 estimatedItemSize、drawDistance 等参数
  • 支持功能: 虚拟化渲染、多列布局、上拉加载、下拉刷新等
  • 测试验证: 确保三端表现一致,性能优异
常用属性快速参考
<FlashList
  data={data}                           // 数据源
  renderItem={renderItem}               // 渲染函数
  keyExtractor={keyExtractor}           // 键提取函数
  estimatedItemSize={280}               // 预估项目大小(重要!)
  numColumns={2}                        // 多列布局
  removeClippedSubviews={true}          // 裁剪不可见区域
  drawDistance={250}                    // 预渲染的绘制距离
  horizontal={false}                    // 横向布局
  ListHeaderComponent={header}          // 列表头部组件
  ListFooterComponent={footer}          // 列表底部组件
  ItemSeparatorComponent={separator}    // 分隔组件
  ListEmptyComponent={empty}            // 空列表组件
  onEndReached={loadMore}               // 上拉加载更多
  onEndReachedThreshold={0.5}           // 触发阈值
  refreshControl={refresh}              // 下拉刷新
  onViewableItemsChanged={callback}     // 可见性变化回调
  viewabilityConfig={config}            // 可见性配置
/>
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐