这段React Native代码实现了一个高性能的虚拟化列表应用,其核心原理基于React Native的VirtualizedList组件和React的状态管理机制。

在数据层面,应用通过useState钩子管理多个状态:原始数据、加载状态、搜索查询和选中项。初始数据通过Array.from生成50个具有唯一ID、标题、描述和收藏状态的对象。搜索功能通过filteredData实现,它根据searchQuery对数据进行实时过滤,只显示标题匹配搜索关键词的项。收藏功能通过handleFavoritePress方法实现,它遍历数据数组并切换指定ID项目的isFavorite状态。

列表渲染优化的关键在于VirtualizedList组件的工作机制。与普通列表不同,VirtualizedList通过getItemCount和getItem这两个关键函数来动态计算和获取列表项,而不是一次性渲染所有数据。initialNumToRender={4}意味着初始只渲染4个可见项,当用户滚动时再按需渲染后续项。这种惰性渲染机制极大地提升了长列表的性能,特别是在移动设备上。keyExtractor确保每个列表项都有稳定的唯一标识,这对于高效的列表更新至关重要。


实际项目演示:

这段React Native代码实现了一个基于VirtualizedList的高性能列表应用,主要原理可以分为数据管理、列表渲染优化和用户交互三个核心层面。

在数据层面,代码使用React的useState钩子来管理应用状态。初始数据通过Array.from方法生成50个具有唯一ID、标题、描述和收藏状态的对象。搜索功能通过filteredData实现,它根据searchQuery状态对数据进行实时过滤,只显示标题匹配搜索关键词的项。收藏功能通过handleFavoritePress方法实现,它遍历数据数组并切换指定ID项目的isFavorite状态。这种不可变数据更新模式确保了状态变化的可追踪性。

import React, { useState } from 'react';
import { SafeAreaView, View, VirtualizedList, StyleSheet, Text, TouchableOpacity, TextInput, ActivityIndicator } from 'react-native';
import Constants from 'expo-constants';

const DATA = Array.from({ length: 50 }, (_, index) => ({
  id: Math.random().toString(12).substring(0),
  title: `Item ${index + 1}`,
  description: `This is the description for item ${index + 1}`,
  isFavorite: false,
}));

const getItem = (data, index) => data[index];
const getItemCount = (data) => data.length;

const Item = ({ title, description, isFavorite, onPress, onFavoritePress }) => {
  return (
    <TouchableOpacity onPress={onPress} style={styles.item}>
      <View style={styles.itemContent}>
        <Text style={styles.title}>{title}</Text>
        <Text style={styles.description}>{description}</Text>
      </View>
      <TouchableOpacity onPress={onFavoritePress} style={styles.favoriteButton}>
        <Text style={styles.favoriteText}>{isFavorite ? '❤️' : '🤍'}</Text>
      </TouchableOpacity>
    </TouchableOpacity>
  );
};

const VirtualizedListExample = () => {
  const [data, setData] = useState(DATA);
  const [loading, setLoading] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');
  const [selectedItem, setSelectedItem] = useState(null);

  const handleRefresh = () => {
    setLoading(true);
    setTimeout(() => {
      setData(DATA);
      setLoading(false);
    }, 1000);
  };

  const handleLoadMore = () => {
    setLoading(true);
    setTimeout(() => {
      const newData = Array.from({ length: 10 }, (_, index) => ({
        id: Math.random().toString(12).substring(0),
        title: `Item ${data.length + index + 1}`,
        description: `This is the description for item ${data.length + index + 1}`,
        isFavorite: false,
      }));
      setData([...data, ...newData]);
      setLoading(false);
    }, 1000);
  };

  const handleItemPress = (item) => {
    setSelectedItem(item);
  };

  const handleFavoritePress = (itemId) => {
    setData(
      data.map((item) =>
        item.id === itemId ? { ...item, isFavorite: !item.isFavorite } : item
      )
    );
  };

  const filteredData = data.filter((item) =>
    item.title.toLowerCase().includes(searchQuery.toLowerCase())
  );

  return (
    <SafeAreaView style={styles.container}>
      <TextInput
        style={styles.searchInput}
        placeholder="Search items..."
        value={searchQuery}
        onChangeText={setSearchQuery}
      />
      {selectedItem && (
        <View style={styles.selectedItemContainer}>
          <Text style={styles.selectedItemTitle}>{selectedItem.title}</Text>
          <Text style={styles.selectedItemDescription}>
            {selectedItem.description}
          </Text>
        </View>
      )}
      <VirtualizedList
        data={filteredData}
        initialNumToRender={4}
        renderItem={({ item }) => (
          <Item
            title={item.title}
            description={item.description}
            isFavorite={item.isFavorite}
            onPress={() => handleItemPress(item)}
            onFavoritePress={() => handleFavoritePress(item.id)}
          />
        )}
        keyExtractor={(item) => item.id}
        getItemCount={getItemCount}
        getItem={getItem}
        onRefresh={handleRefresh}
        refreshing={loading}
      />
      <TouchableOpacity onPress={handleLoadMore} style={styles.loadMoreButton}>
        {loading ? (
          <ActivityIndicator color="#fff" />
        ) : (
          <Text style={styles.loadMoreText}>Load More</Text>
        )}
      </TouchableOpacity>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: Constants.statusBarHeight,
  },
  searchInput: {
    padding: 10,
    margin: 16,
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 8,
  },
  item: {
    backgroundColor: '#f9c2ff',
    height: 100,
    justifyContent: 'space-between',
    marginVertical: 8,
    marginHorizontal: 16,
    padding: 20,
    borderRadius: 8,
    flexDirection: 'row',
    alignItems: 'center',
  },
  itemContent: {
    flex: 1,
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
  },
  description: {
    fontSize: 14,
    color: '#666',
  },
  favoriteButton: {
    padding: 10,
  },
  favoriteText: {
    fontSize: 20,
  },
  selectedItemContainer: {
    padding: 16,
    backgroundColor: '#e6e6e6',
    marginHorizontal: 16,
    borderRadius: 8,
    marginBottom: 8,
  },
  selectedItemTitle: {
    fontSize: 16,
    fontWeight: 'bold',
  },
  selectedItemDescription: {
    fontSize: 14,
    color: '#666',
  },
  loadMoreButton: {
    backgroundColor: '#6200ee',
    padding: 16,
    margin: 16,
    borderRadius: 8,
    alignItems: 'center',
  },
  loadMoreText: {
    color: '#fff',
    fontWeight: 'bold',
  },
});

export default VirtualizedListExample;

列表渲染优化的核心在于VirtualizedList组件。与普通FlatList不同,VirtualizedList通过getItemCount和getItem这两个关键函数来动态计算和获取列表项,而不是一次性渲染所有数据。initialNumToRender={4}意味着初始只渲染4个可见项,当用户滚动时再按需渲染后续项。这种惰性渲染机制极大地提升了长列表的性能,特别是在移动设备上。keyExtractor确保每个列表项都有稳定的唯一标识,这对于高效的列表更新至关重要。

用户交互层面实现了完整的操作闭环。搜索输入框通过TextInput组件提供实时搜索功能,onChangeText直接更新searchQuery状态。下拉刷新功能通过onRefresh和refreshing属性实现,handleRefresh方法在触发后模拟1秒的网络延迟,然后重置数据到初始状态。"加载更多"功能通过handleLoadMore实现,它在现有数据末尾添加10个新项目,模拟分页加载场景。项目选择功能通过handleItemPress记录当前选中的项目,并在列表上方显示选中项的详细信息。

在这里插入图片描述

整个应用的UI布局采用SafeAreaView确保内容不会与设备刘海或状态栏重叠。样式系统通过StyleSheet.create创建,提供一致的视觉设计,包括圆角边框、阴影效果和合理的间距。加载状态通过ActivityIndicator组件可视化显示,在异步操作期间提供用户反馈。这种架构既保证了大数据量下的流畅体验,又提供了丰富的交互功能,展示了React Native在构建复杂列表界面时的最佳实践。


打包

接下来通过打包命令npn run harmony将reactNative的代码打包成为bundle,这样可以进行在开源鸿蒙OpenHarmony中进行使用。

在这里插入图片描述
最后运行效果图如下显示:

请添加图片描述
用户交互层面实现了完整的操作闭环。搜索输入框通过TextInput组件提供实时搜索功能,onChangeText直接更新searchQuery状态。下拉刷新功能通过onRefresh和refreshing属性实现,handleRefresh方法在触发后模拟1秒的网络延迟,然后重置数据到初始状态。"加载更多"功能通过handleLoadMore实现,它在现有数据末尾添加10个新项目,模拟分页加载场景。项目选择功能通过handleItemPress记录当前选中的项目,并在列表上方显示选中项的详细信息。

整个应用的UI布局采用SafeAreaView确保内容不会与设备刘海或状态栏重叠。样式系统通过StyleSheet.create创建,提供一致的视觉设计,包括圆角边框、阴影效果和合理的间距。加载状态通过ActivityIndicator组件可视化显示,在异步操作期间提供用户反馈。这种架构既保证了大数据量下的流畅体验,又提供了丰富的交互功能,展示了React Native在构建复杂列表界面时的最佳实践。

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐