You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中FlatList展示800个emoji的性能优化求助

React Native 800+ Emoji 列表性能优化方案

我开发了一个按类别展示emoji的React Native页面,包含约800个emoji,采用嵌套FlatList实现,但存在两个核心问题:

  • emoji在设备上渲染耗时过长
  • 渲染完成后屏幕操作卡顿,点击emoji响应延迟

原实现代码

import { 
    StyleSheet,
    View,
    Text,
    TouchableOpacity,
    FlatList,
    SafeAreaView
} from 'react-native';
import emojis from './emojis.json';
import { useState } from 'react';

export default function App() {
  
  const [isLoadingEmojis, setIsLoadingEmojis] = useState(true);

  const renderCategoryEmoji = (categoryEmoji) => {
    return (
      <View key={categoryEmoji.categoryId} style={{marginBottom: 10}}>
          <Text style={styles.categoryLabel}>{categoryEmoji.categoryName}</Text>
          <FlatList
              data={categoryEmoji.emojis}
              renderItem={renderEmojiItem}
              keyExtractor={(item) => item.id.toString()}
              numColumns={7}
              contentContainerStyle={{paddingBottom: 100}}
              onLayout={() => setIsLoadingEmojis(false)}
          />
      </View>
    );
  }    

  const renderEmojiItem = ({ item }) => {
    return (
      <View>
        <TouchableOpacity style={{ width: 47, height: 47, margin: 1}}>
          <Text style={{color: 'black', fontSize: 25}}>
            {item.emoji}
          </Text>
        </TouchableOpacity>
      </View>
    );
  }

  return (
    <SafeAreaView style={styles.container}>
      <FlatList style={{margin: 15, marginBottom: 50}}
        data={emojis}
        renderItem={({ item }) => renderCategoryEmoji(item)}
        keyExtractor={(item) => item.categoryId.toString()}
      />
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    margin: 0,
    marginTop: 30,
    display: "flex",
    flexDirection: "column",
  },
  categoryLabel: {
        fontSize: 18,
        fontWeight: 'bold',
        marginVertical: 10,
    },
});

针对性优化建议

1. 替换嵌套FlatList为SectionList

嵌套FlatList会带来双重视图缓存和布局计算开销,是性能瓶颈的核心原因。改用SectionList可以在单一列表中实现分组展示,大幅减少渲染开销:

import { SectionList } from 'react-native';
import { useMemo, memo } from 'react';

export default function App() {
  const [isLoadingEmojis, setIsLoadingEmojis] = useState(true);

  // 预生成分组数据,避免每次渲染重复计算
  const sections = useMemo(() => {
    return emojis.map(category => ({
      title: category.categoryName,
      data: category.emojis
    }));
  }, []);

  // 用memo包裹子组件,避免不必要重渲染
  const RenderEmojiItem = memo(({ item }) => {
    return (
      <TouchableOpacity style={{ width: 47, height: 47, margin: 1, justifyContent: 'center', alignItems: 'center'}}>
        <Text style={{color: 'black', fontSize: 25}}>{item.emoji}</Text>
      </TouchableOpacity>
    );
  });

  return (
    <SafeAreaView style={styles.container}>
      <SectionList
        sections={sections}
        keyExtractor={(item) => item.id.toString()}
        renderSectionHeader={({ section }) => (
          <Text style={styles.categoryLabel}>{section.title}</Text>
        )}
        renderItem={({ item }) => <RenderEmojiItem item={item} />}
        numColumns={7}
        contentContainerStyle={{ padding: 15, paddingBottom: 50 }}
        onLayout={() => setIsLoadingEmojis(false)}
        removeClippedSubviews={true}
        maxToRenderPerBatch={20}
        windowSize={5}
      />
    </SafeAreaView>
  );
}

2. 组件级优化:避免不必要重渲染

  • 用React.memo包裹RenderEmojiItem,只有当item属性变化时才重新渲染
  • 用useMemo缓存分组数据,防止每次渲染重复处理emojis数组

3. 优化列表性能属性

  • removeClippedSubviews={true}:自动销毁屏幕外的视图,降低内存占用
  • maxToRenderPerBatch={20}:控制每次批量渲染的数量,避免一次性渲染过多元素导致卡顿
  • windowSize={5}:缩小预渲染范围,减少后台渲染的视图数量

4. 简化视图层级

移除renderEmojiItem中多余的外层View,直接用TouchableOpacity作为根组件,减少视图树深度,降低渲染计算量

5. 修复加载状态逻辑

原代码中每个子FlatList的onLayout都会触发setIsLoadingEmojis(false),导致多次状态更新和重渲染。改为只在根列表的onLayout中设置一次加载完成即可。


内容的提问来源于stack exchange,提问作者araraujo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 03:09:54