본문 바로가기
FE Development/React-Native

트러블 슈팅 - FlatList 최적화

by 개발자 데이빗 2022. 1. 13.

문제가 되었던 사항

  1. Flatlist로 페이지네이션한 리스트의 항목이 70개 이상이 되는 경우 눈에 띄게 버벅이는 현상
  2. ListHeaderComponent에 넘긴 TextInput에서 한글자 입력할때마다 키보드 창이 dismiss되는 현상

해결과정

Flatlist 최적화 방법에 대하여 찾아보며 문제를 해결하였다.

 

1번 문제의 경우 유니크한 key값을 지정하지 않아 발생한 이슈였으며

 

2번 문제의 경우 인라인 함수 작성으로 인해 한글자 입력시마다 (setState 호출시마다) 상태 변화로 인해 ListHeaderComponent로 넘긴 함수가 재호출 되어 발생한 이슈였다.

 

기존 코드 예시

 

// render header
const renderHeaderView = () => (
	<HeaderView
  	  onChange={handleTextChange}
  	  keyword={keyword}
	/>
);

...

<FlatList
  data={data}
  renderItem={renderItem}
  keyExtractor={({ name }) => name}
  contentContainerStyle={{ flexGrow: 1 }}
  ListEmptyComponent={renderEmptyView}
  ListHeaderComponent={renderHeaderView}
/>

 

개선 코드 예시

...

<FlatList
  data={dictionaryItems}
  renderItem={renderItem}
  keyExtractor={({ _id }) => _id} // 유니크한 값으로 지정
  contentContainerStyle={{ flexGrow: 1 }}
  ListEmptyComponent={renderEmptyView}
  ListHeaderComponent={( // 컴포넌트를 직접 주입해 재호출 방지
	<HeaderView
  	  onChange={handleTextChange}
  	  keyword={keyword}
	/>
  )}
/>

 

개선 코드 예시

 

Flastlist 최적화에 관련된 React Native Docs

https://reactnative.dev/docs/optimizing-flatlist-configuration

 

Optimizing Flatlist Configuration · React Native

Terms

reactnative.dev

 

ScrollView와 Flatlist의 차이점

  • Scroll View
    • 메모리 관리 없음
    • 모든 콘텐츠 한번에 불러옴
    • Scroll position 보존되지 않음
    • 눈에 띄는 프레임 드랍
    • 데이터 갱신 시 issue
  • Flatlist 
    • 자동 메모리 관리
    • 스크롤에 따라 콘텐츠 로드
    • Scroll Position 보존되지 않음
    • 빠른 Scroll Event 발생 시 화면이 깜빡 거리는 이슈
    • 복잡한 template 사용시 프레임 드랍
    • Scroll 매우 빠르게 작동 시 빈화면이 보이거나 렌더링이 늦어짐

 

최적화 정리

 

React.Component 와 React.PureComponent의 차이

React.Component 와 React.PureComponent 는 서로 매우 유사하지만 매우 다른점이 있다.

React.PureComponent에는 React의 생명주기중 하나인 shouldComponentUpdate가 기본적으로 구현되어 있는것이다.

props와 state의 얕은(shallow) 비교를 통해 비교한 뒤 변경사항이 있을경우만 리렌더링 해주기 때문에 굳이shouldComponentUpdate를 신경쓰지 않아도 된다.

복잡한 데이터의 구조를 가지고 있다면 의도치 않은 결과를 가져올수도 있다는 점에 유의해 PureComponent를 사용한다면 성능향상에 도움이 된다.

 

불필요한 Backtick 사용 자제

backtick은 내부에서 함수를 한번 거쳐 실행되고 리턴되는 과정을 거치기 때문에 불필요하게 사용하지 않는다.

 

인라인 함수 사용 자제

인라인 함수로 코드를 작성하게 되면 렌더를 하면서 코드를 읽는 과정중에 함수를 그대로 모두 읽으면서 퍼포먼스를 조금씩 더 차지하는 코드였다.

하지만 일반 함수로 코드를 작성한다면 렌더를 하면서 그 함수를 참조만 하기 때문에 퍼포먼스를 차지하는 것을 최대한으로 줄여 성능향상에 도움이 될 것이다.

예시로 

 

유니크한 key를 설정

Flat List는 화면에 보여지는 부분만 렌더링 하는데

렌더 아이템을 캐싱하고 다시 불러올때  key를 추적하기 때문에 유니크 key를 설정해 주어야 성능 향상

 

오버드로우

앱은 한 프레임 내에 동일한 픽셀을 두 번 이상 그릴 수 있으며 이러한 작업을 오버드로우 이벤트라고 한다.

일반적으로 오버드로우는 불필요하며 제거하는 것이 가장 좋다.

오버드로우는 사용자가 화면에서 보는 것과 상관없는 픽셀을 렌더링하기 위해 GPU 시간을 낭비하여 성능 문제로 나타납니다.

기본적으로 모든 어플리케이션은 어느정도의 오버드로우를 실행하지만 또한 너무 많아 진다면 성능상의 문제도 있고 그이상이라면 아예작동하지 않을 수도 있다.

 

웹에 비해 화면이 작은 앱에서는 map (ScrollView)을 사용하면 있는 모든 데이터를 렌더하면서 오버드로우 현상이 계속적으로 늘어날 수 있어 map을 사용하기에는 적합하지 않다.

Flatlist나 Sectionlist는 map과는 다르게 현재 화면에 보여질 수 있는 데이터만을 우선적으로 가져오기 때문에 그러한 현상을 줄일 수 있게 된다.

 

최적화 관련 Props

 

getItemLayout 

getItemLayout 속성을 정의해 주면 item의 레이아웃 크기가 매번 계산되지 않아도 되므로 성능 개선에 효과적이다.

 

initialNumToRender

최초 몇 개의 item을 렌더할지 명시해 주는 옵션으로, 초기 렌더링 선능을 향상할 수 있다.

단, 아이템 높이와 화면에서 FlatList 영역의 높이를 고려해 빈 곳이 발생하지 않도록 해야 한다.

 

maxToRenderPerBatch

스크롤 시 렌더링 할 항목의 수를 결정한다.

보이는 화면의 렌더링 항목 수라고 볼 수 있다.

기본 값이 10으로 설정되어 있기 때문에 item 크기와 FlatList 영역의 높이에 따라 실제로 필요한 최적의 숫자로 설정해 주는 것이 좋다.

 

windowSize

FlatList 영역의 높이 외부에서 렌더링 되는 최대 항목수를 결정해 주는 옵션이다.

보이지 않는 화면의 항목 수를 포함하는 범위라고 볼 수 있다.

이 속성에 전달되는 숫자 1은 FlatList 영역의 높이와 같으며, 기본값이 21인데 현재 스크린을 기준으로 앞으로 10개, 뒤로 10개를 추가로 렌더링 한다는 뜻이다.

 

removeClippedSubviews

true 설정하는 경우 화면에서 벗어난 아이템을 unmount하여 메모리를 아껴준다.

댓글