Skip to content

FlatList(列表组件)

React Native 核心基础

在 React Native 中,FlatList 是用于渲染长列表的高性能组件。它是 ScrollView 的优化版本,支持虚拟化,只渲染可见的项目,从而提高性能。

1. 什么是 FlatList 组件?

FlatList 组件是 React Native 中用于渲染长列表的高性能组件。它支持虚拟化,只渲染当前可见的项目,而不是整个列表,从而大大提高了性能。

主要功能

  • 虚拟化:只渲染可见的项目,提高性能
  • 下拉刷新:支持下拉刷新功能
  • 上拉加载:支持上拉加载更多功能
  • 水平滚动:支持水平列表
  • 分割线:支持添加分割线
  • 头部和尾部:支持添加列表头部和尾部

2. 基本用法

简单列表

jsx
import { FlatList, View, Text, StyleSheet } from 'react-native';

export default function SimpleFlatList() {
  const data = Array.from({ length: 50 }, (_, i) => ({ id: i, title: `Item ${i + 1}` }));

  const renderItem = ({ item }) => (
    <View style={styles.item}>
      <Text>{item.title}</Text>
    </View>
  );

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={(item) => item.id.toString()}
    />
  );
}

const styles = StyleSheet.create({
  item: {
    height: 50,
    backgroundColor: '#f0f0f0',
    marginVertical: 5,
    marginHorizontal: 10,
    alignItems: 'center',
    justifyContent: 'center',
  },
});

带分割线的列表

jsx
import { FlatList, View, Text, StyleSheet } from 'react-native';

export default function FlatListWithSeparator() {
  const data = Array.from({ length: 50 }, (_, i) => ({ id: i, title: `Item ${i + 1}` }));

  const renderItem = ({ item }) => (
    <View style={styles.item}>
      <Text>{item.title}</Text>
    </View>
  );

  const ItemSeparatorComponent = () => (
    <View style={styles.separator} />
  );

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={(item) => item.id.toString()}
      ItemSeparatorComponent={ItemSeparatorComponent}
    />
  );
}

const styles = StyleSheet.create({
  item: {
    height: 50,
    backgroundColor: '#f0f0f0',
    marginHorizontal: 10,
    alignItems: 'center',
    justifyContent: 'center',
  },
  separator: {
    height: 1,
    backgroundColor: '#ccc',
    marginHorizontal: 10,
  },
});

带头部和尾部的列表

jsx
import { FlatList, View, Text, StyleSheet } from 'react-native';

export default function FlatListWithHeaderFooter() {
  const data = Array.from({ length: 20 }, (_, i) => ({ id: i, title: `Item ${i + 1}` }));

  const renderItem = ({ item }) => (
    <View style={styles.item}>
      <Text>{item.title}</Text>
    </View>
  );

  const ListHeaderComponent = () => (
    <View style={styles.header}>
      <Text style={styles.headerText}>List Header</Text>
    </View>
  );

  const ListFooterComponent = () => (
    <View style={styles.footer}>
      <Text style={styles.footerText}>List Footer</Text>
    </View>
  );

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={(item) => item.id.toString()}
      ListHeaderComponent={ListHeaderComponent}
      ListFooterComponent={ListFooterComponent}
    />
  );
}

const styles = StyleSheet.create({
  item: {
    height: 50,
    backgroundColor: '#f0f0f0',
    marginVertical: 5,
    marginHorizontal: 10,
    alignItems: 'center',
    justifyContent: 'center',
  },
  header: {
    height: 100,
    backgroundColor: '#007AFF',
    alignItems: 'center',
    justifyContent: 'center',
    marginBottom: 10,
  },
  headerText: {
    color: 'white',
    fontSize: 20,
    fontWeight: 'bold',
  },
  footer: {
    height: 100,
    backgroundColor: '#007AFF',
    alignItems: 'center',
    justifyContent: 'center',
    marginTop: 10,
  },
  footerText: {
    color: 'white',
    fontSize: 20,
    fontWeight: 'bold',
  },
});

3. 常用属性

核心属性

属性描述示例
data列表数据data={[{ id: 1, title: 'Item 1' }]}
renderItem渲染每个项目的函数renderItem={({ item }) => <Text>{item.title}</Text>}
keyExtractor提取每个项目的唯一键keyExtractor={(item) => item.id.toString()}
horizontal是否水平滚动horizontal={true}
showsVerticalScrollIndicator是否显示垂直滚动条showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator是否显示水平滚动条showsHorizontalScrollIndicator={false}
contentContainerStyle内容容器样式contentContainerStyle={ { padding: 10 } }
style样式对象style={styles.list}

列表组件属性

属性描述示例
ItemSeparatorComponent分割线组件ItemSeparatorComponent={() => <View style={styles.separator} />}
ListHeaderComponent头部组件ListHeaderComponent={() => <View style={styles.header} />}
ListFooterComponent尾部组件ListFooterComponent={() => <View style={styles.footer} />}
ListEmptyComponent空列表组件ListEmptyComponent={() => <Text>No data</Text>}

滚动属性

属性描述示例
onRefresh下拉刷新回调onRefresh={() => fetchData()}
refreshing是否正在刷新refreshing={isRefreshing}
onEndReached滚动到底部回调onEndReached={() => loadMore()}
onEndReachedThreshold触发 onEndReached 的阈值onEndReachedThreshold={0.1}

4. 高级用法

下拉刷新

jsx
import { FlatList, View, Text, StyleSheet, RefreshControl } from 'react-native';
import { useState } from 'react';

export default function FlatListWithRefresh() {
  const [data, setData] = useState(Array.from({ length: 20 }, (_, i) => ({ id: i, title: `Item ${i + 1}` })));
  const [refreshing, setRefreshing] = useState(false);

  const onRefresh = () => {
    setRefreshing(true);
    // 模拟网络请求
    setTimeout(() => {
      const newData = Array.from({ length: 20 }, (_, i) => ({ id: i, title: `Item ${i + 1} (Refreshed)` }));
      setData(newData);
      setRefreshing(false);
    }, 1500);
  };

  const renderItem = ({ item }) => (
    <View style={styles.item}>
      <Text>{item.title}</Text>
    </View>
  );

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={(item) => item.id.toString()}
      refreshControl={
        <RefreshControl
          refreshing={refreshing}
          onRefresh={onRefresh}
          colors={['#007AFF']} // iOS
          tintColor="#007AFF" // Android
        />
      }
    />
  );
}

const styles = StyleSheet.create({
  item: {
    height: 50,
    backgroundColor: '#f0f0f0',
    marginVertical: 5,
    marginHorizontal: 10,
    alignItems: 'center',
    justifyContent: 'center',
  },
});

上拉加载更多

jsx
import { FlatList, View, Text, StyleSheet, ActivityIndicator } from 'react-native';
import { useState } from 'react';

export default function FlatListWithLoadMore() {
  const [data, setData] = useState(Array.from({ length: 20 }, (_, i) => ({ id: i, title: `Item ${i + 1}` })));
  const [loading, setLoading] = useState(false);

  const loadMore = () => {
    if (loading) return;
    
    setLoading(true);
    // 模拟网络请求
    setTimeout(() => {
      const newData = Array.from({ length: 10 }, (_, i) => ({ id: data.length + i, title: `Item ${data.length + i + 1}` }));
      setData([...data, ...newData]);
      setLoading(false);
    }, 1500);
  };

  const renderItem = ({ item }) => (
    <View style={styles.item}>
      <Text>{item.title}</Text>
    </View>
  );

  const ListFooterComponent = () => {
    if (!loading) return null;
    return (
      <View style={styles.loadingContainer}>
        <ActivityIndicator size="small" color="#007AFF" />
        <Text style={styles.loadingText}>Loading...</Text>
      </View>
    );
  };

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={(item) => item.id.toString()}
      onEndReached={loadMore}
      onEndReachedThreshold={0.1}
      ListFooterComponent={ListFooterComponent}
    />
  );
}

const styles = StyleSheet.create({
  item: {
    height: 50,
    backgroundColor: '#f0f0f0',
    marginVertical: 5,
    marginHorizontal: 10,
    alignItems: 'center',
    justifyContent: 'center',
  },
  loadingContainer: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  loadingText: {
    marginLeft: 10,
    fontSize: 16,
  },
});

水平列表

jsx
import { FlatList, View, Text, StyleSheet } from 'react-native';

export default function HorizontalFlatList() {
  const data = Array.from({ length: 20 }, (_, i) => ({ id: i, title: `Item ${i + 1}` }));

  const renderItem = ({ item }) => (
    <View style={styles.item}>
      <Text>{item.title}</Text>
    </View>
  );

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={(item) => item.id.toString()}
      horizontal
      showsHorizontalScrollIndicator={false}
      contentContainerStyle={styles.container}
    />
  );
}

const styles = StyleSheet.create({
  container: {
    paddingVertical: 20,
  },
  item: {
    width: 100,
    height: 100,
    backgroundColor: '#f0f0f0',
    marginHorizontal: 10,
    alignItems: 'center',
    justifyContent: 'center',
  },
});

5. 性能优化

1. 确保 keyExtractor 返回唯一键

jsx
// 推荐
<FlatList
  data={data}
  renderItem={renderItem}
  keyExtractor={(item) => item.id.toString()}
/>

// 不推荐
<FlatList
  data={data}
  renderItem={renderItem}
  keyExtractor={(item, index) => index.toString()}
/>

2. 使用 React.memo 优化渲染

jsx
import React, { memo } from 'react';
import { View, Text, StyleSheet } from 'react-native';

const Item = memo(({ title }) => {
  console.log('Item rendered');
  return (
    <View style={styles.item}>
      <Text>{title}</Text>
    </View>
  );
});

export default function OptimizedFlatList() {
  const data = Array.from({ length: 50 }, (_, i) => ({ id: i, title: `Item ${i + 1}` }));

  const renderItem = ({ item }) => (
    <Item title={item.title} />
  );

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={(item) => item.id.toString()}
    />
  );
}

const styles = StyleSheet.create({
  item: {
    height: 50,
    backgroundColor: '#f0f0f0',
    marginVertical: 5,
    marginHorizontal: 10,
    alignItems: 'center',
    justifyContent: 'center',
  },
});

3. 避免在 renderItem 中创建新函数

jsx
// 推荐
const renderItem = useCallback(({ item }) => (
  <Item title={item.title} onPress={() => handlePress(item.id)} />
), []);

// 不推荐
const renderItem = ({ item }) => (
  <Item title={item.title} onPress={() => handlePress(item.id)} />
);

4. 使用 getItemLayout 优化布局计算

jsx
<FlatList
  data={data}
  renderItem={renderItem}
  keyExtractor={(item) => item.id.toString()}
  getItemLayout={(data, index) => ({
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  })}
/>

6. 常见错误与解决方案

错误 1:列表不显示

错误

jsx
import { FlatList, View, Text } from 'react-native';

export default function App() {
  const data = [{ id: 1, title: 'Item 1' }, { id: 2, title: 'Item 2' }];

  return (
    <FlatList
      data={data}
      renderItem={(item) => <Text>{item.title}</Text>} // 错误:renderItem 接收的是对象,不是直接的 item
    />
  );
}

解决方案

jsx
import { FlatList, View, Text } from 'react-native';

export default function App() {
  const data = [{ id: 1, title: 'Item 1' }, { id: 2, title: 'Item 2' }];

  return (
    <FlatList
      data={data}
      renderItem={({ item }) => <Text>{item.title}</Text>} // 正确:使用解构获取 item
      keyExtractor={(item) => item.id.toString()}
    />
  );
}

错误 2:keyExtractor 未提供

错误

jsx
import { FlatList, View, Text } from 'react-native';

export default function App() {
  const data = [{ id: 1, title: 'Item 1' }, { id: 2, title: 'Item 2' }];

  return (
    <FlatList
      data={data}
      renderItem={({ item }) => <Text>{item.title}</Text>} // 错误:没有提供 keyExtractor
    />
  );
}

解决方案

jsx
import { FlatList, View, Text } from 'react-native';

export default function App() {
  const data = [{ id: 1, title: 'Item 1' }, { id: 2, title: 'Item 2' }];

  return (
    <FlatList
      data={data}
      renderItem={({ item }) => <Text>{item.title}</Text>}
      keyExtractor={(item) => item.id.toString()} // 正确:提供了 keyExtractor
    />
  );
}

错误 3:列表性能问题

错误:在 renderItem 中创建复杂组件或执行复杂计算

解决方案

  • 使用 React.memo 包装列表项组件
  • 避免在 renderItem 中创建新函数
  • 使用 useCallback 缓存回调函数
  • 对于复杂的列表项,考虑使用 PureComponentReact.memo

7. 最佳实践

1. 数据处理

  • 确保数据有唯一的 ID 字段
  • 预处理数据,避免在 renderItem 中进行复杂计算
  • 对于大型数据集,考虑使用分页加载

2. 性能优化

  • 使用 React.memo 包装列表项组件
  • 提供 keyExtractor 函数
  • 使用 getItemLayout 优化布局计算
  • 避免在 renderItem 中创建新函数

3. 用户体验

  • 为列表添加下拉刷新功能
  • 为列表添加加载更多功能
  • 为空列表添加占位符
  • 为加载状态添加加载指示器

4. 布局考虑

  • 为列表项设置固定的高度,以便 getItemLayout 优化
  • 合理设置 onEndReachedThreshold,避免频繁触发加载更多
  • 对于水平列表,确保设置了适当的容器高度

8. 总结

FlatList 是 React Native 中用于渲染长列表的高性能组件。通过合理使用 FlatList 组件,你可以创建出流畅、响应式的列表界面。

在使用 FlatList 组件时,要注意:

  1. 提供 keyExtractor 函数,确保每个项目有唯一的键
  2. 使用 React.memo 包装列表项组件,优化渲染性能
  3. 为列表添加下拉刷新和加载更多功能,提升用户体验
  4. 避免在 renderItem 中创建新函数,减少不必要的重新渲染

掌握 FlatList 组件的使用,是创建高性能 React Native 应用的关键。在接下来的教程中,我们将学习更多的高级组件和功能。

© 2026 编程马·菜鸟教程 版权所有