React Native에서 FlatList 성능 개선하기

문제 상황

상품 목록 화면에서 500개 이상의 아이템을 렌더링할 때 스크롤이 버벅이는 현상이 발생했다. 특히 Android에서 심했고, 이미지가 포함된 복잡한 레이아웃이라 더 느렸다.

적용한 최적화

1. getItemLayout 구현

아이템 높이가 고정되어 있다면 getItemLayout을 반드시 구현해야 한다. FlatList가 스크롤 위치를 계산하는 비용을 크게 줄일 수 있다.

getItemLayout={(data, index) => ({
  length: ITEM_HEIGHT,
  offset: ITEM_HEIGHT * index,
  index,
})}

2. keyExtractor 최적화

기본 keyExtractor는 index를 사용하는데, 데이터가 변경될 때 불필요한 리렌더를 유발한다.

keyExtractor={(item) => item.id.toString()}

3. removeClippedSubviews 활성화

Android에서 화면 밖의 뷰를 제거해 메모리를 절약한다.

<FlatList
  removeClippedSubviews={true}
  maxToRenderPerBatch={10}
  windowSize={10}
/>

4. shouldComponentUpdate 구현

renderItem에 전달되는 컴포넌트를 PureComponent로 변경하거나 React.memo로 감쌌다.

const ProductItem = React.memo(({ item }) => {
  return (
    <View style={styles.item}>
      <Image source={{ uri: item.imageUrl }} />
      <Text>{item.name}</Text>
    </View>
  );
});

결과

위 최적화를 모두 적용한 결과 Android에서도 부드러운 스크롤을 유지할 수 있었다. 특히 getItemLayoutremoveClippedSubviews의 효과가 컸다. 개발자 메뉴의 Perf Monitor로 확인했을 때 60fps에 근접한 수치가 나왔다.

복잡한 리스트 화면을 만들 때는 처음부터 이런 최적화를 염두에 두고 설계하는 게 중요하다는 걸 다시 한번 느꼈다.