[번역] FlatList 최적화하기

aborile·2023년 5월 7일
2

React Native

목록 보기
3/8
post-thumbnail

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

용어 정리

VirtualizedList

FlatList를 이루고 있는 컴포넌트 (Virtual List의 컨셉을 React Native에서 구현한 것)

Memory comsupmtion (메모리 사용량)

메모리에 저장되는 list의 정보 양. 앱 충돌로 이어질 수 있다.

Responsiveness (반응성)

애플리케이션이 사용자의 상호작용에 반응하는 능력. 예를 들어, 반응성이 낮다는 것은 컴포넌트를 터치했을 때 예상대로 즉시 반응하지 않고 응답을 약간 기다려야하는 경우를 가리킨다.

Blank areas (빈 영역)

VirtualizedList가 아이템을 충분히 빠르게 렌더링할 수 없는 경우, list에서 렌더링되지 않은 컴포넌트는 빈 공간으로 표시된다.

Viewport (뷰포트)

픽셀로 렌더링되는 콘텐츠가 보이는 영역

Window (윈도우)

아이템을 마운트하는 영역. 일반적으로 뷰포트보다 훨씬 크다.

Props

FlatList의 성능을 향상시킬 수 있는 props는 다음과 같다.

removeClippedSubviews

TypeDefault
BooleanFalse

true로 지정하면, 뷰포트의 바깥에 있는 view는 native view hierarchy에서 분리된다.

장점

네이티브 렌더링과 드로잉 순회에서 viewport 밖에 있는 view는 제외되므로, 메인 스레드에서 소요되는 시간이 줄어들기 때문에 프래임 손실 위험이 줄어든다.

단점

이 구현사항은 컨텐츠 누락(주로 iOS에서)과 같은 버그가 있을 수 있다. 특히 transform, absolute positioning 같은 복잡한 작업을 수행하는 경우 더욱 그렇다.
또한 이것은 view가 할당해제(deallocate)되는 것이 아니라 분리(detach)되는 것에 불과하기 때문에 상당한 수준의 메모리가 절약되지는 않는다는 점에 유의해야 한다.

maxToRenderPerBatch

TypeDefault
Number10

FlatList를 통해 전달될 수 있는 VirtualizedList의 prop으로, 배치(각 스크롤에서 렌더링되는 항목의 다음 청크) 당 렌더링할 아이템의 숫자를 조정한다.

장점

큰 숫자로 설정할수록 스크롤 시 빈 영역이 적게 보인다.

단점

배치 당 많은 아이템을 렌더링할수록 JavaScript의 실행 시간이 길어지기 때문에 press같은 다른 이벤트의 처리가 차단되어 반응성이 저하될 수 있다.

updateCellsBatchingPeriod

TypeDefault
Number50

maxToRenderPerBatch가 배치당 렌더링할 아이템의 수를 결정한다면, updateCellsBatchingPeriodVirtualizedList의 배치가 렌더링될 때 걸리는 지연을 milliseconds 단위로 나타낸다. (즉, 컴포넌트가 windowed item을 렌더링하는 빈도)

장점

maxToRenderPerBatch와 같이 사용해서 한번에 많은 아이템을 렌더링하는 대신 배치 빈도를 적게 하거나, 배치 빈도를 높게 하고 적은 아이템을 렌더링하는 등의 설정을 할 수 있다.

단점

배치 빈도가 적으면 빈 영역이 더 많이 발생할 수 있고, 배치 빈도가 잦으면 반응성 문제를 일으킬 수 있다.

initialNumToRender

TypeDefault
Number10

최초에 렌더링 할 아이템의 개수.

장점

모든 기기의 스크린을 덮을 정확한 항목의 수를 정의할 수 있다. 초기 렌더링의 성능을 크게 향상시킬 수 있다.

단점

initialNumToRender를 낮게 설정하면 빈 영역이 발생할 수 있다. (특히, 초기 렌더링에서 뷰포트를 모두 덮기에 너무 작은 경우)

windowSize

TypeDefault
Number21

window 크기를 측정하는 단위로, 숫자 1이 viewport의 높이에 해당한다. 기본 값은 21으로, 위로 10개의 뷰포트, 아래에 10개의 뷰포트, 그리고 사이에 하나를 의미한다.

장점

windowSize가 클수록 스크롤 시 빈 공간이 보일 가능성이 줄어든다. 반면, windowSize가 작을수록 동시에 마운트되는 아이템의 수가 적어지므로 메모리가 절약된다.

단점

windowSize가 클수록 더 많은 메모리를 소비하게 되고, windowSize가 작을수록 빈 영역을 볼 가능성이 커진다.

List items

아래 항목들은 list item 컴포넌트에 대한 몇 가지 팁이다. 이는 list의 핵심이므로 빨라야 한다.

간단한 컴포넌트 사용

컴포넌트가 복잡할수록 렌더링 속도가 느려진다. list의 아이템에는 많은 로직과 중첩을 피하는 게 좋다. 앱에서 list item 컴포넌트를 많이 재사용하는 경우, 큰 list에 대한 컴포넌트를 따로 만들고, 가능한 적은 로직과 중첩을 사용하자.

가벼운 컴포넌트 사용

컴포넌트가 무거울수록 렌더링 속도가 느려진다. 무거운 이미지의 사용을 피하고, 크롭된 이미지 또는 썸네일같이 가능한 작은 이미지를 사용하자. 디자인 팀과 대화해서 list에 가능한 적은 효과와 상호작용을 사용하고 정보를 적게 넣을 수 있게 하고, 그러한 정보는 아이템의 세부 사항에서 표시하게 하자.

shouldComponentUpdate 사용

컴포넌트에 대한 업데이트 확인을 구현하자. React의 PureComponentshouldComponentUpdate를 통해 얕은 비교를 구현할 수 있다. 이것은 모든 props를 확인해야 하기 때문에 비용이 많이 들 수 있다. bit-level의 성능 향상을 원한다면, list item 컴포넌트에 대한 엄격한 규칙을 만들어 잠재적으로 변경될 수 있는 props만 확인하도록 구현하면 된다. list가 충분히 간단하다면 다음과 같이 사용할 수도 있다.

shouldComponentUpdate() {
  return false
}

캐시된 최적화 이미지 사용

보다 성능이 뛰어난 이미지를 위해 @DylanVannreact-native-fast-image 같은 커뮤니티 패키지를 도입할 수 있다. list의 모든 이미지는 new Image() 인스턴스이므로, loaded hook에 빨리 도달할수록 JavaScript 스레드가 다시 해제되는 속도가 빨라진다.

getItemLayout 사용

모든 list item 컴포넌트의 높이(가로 list라면 너비)가 동일하다면, getItemLayout prop을 통해 FlatList가 비동기 레이아웃 계산을 관리하지 않아도 되게 할 수 있다. 이것은 매우 바람직한 최적화 기술이다.

컴포넌트의 크기가 동적인데 실제로 성능 향상이 필요한 경우, 더 나은 성능을 위해 디자인을 다시 할 수 있는지 디자인팀에 문의하는 것을 고려해봄직하다.

keyExtractor 또는 key 사용

FlatListkeyExtractor를 설정하여 캐싱과 아이템 재정렬을 추적하기 위한 React key로 사용할 수 있다.

아이템 컴포넌트에 key prop을 사용할 수도 있다.

renderItem에 익명 함수 지양

renderItem의 함수를 render 함수의 외부로 옮겨 렌더링 함수가 호출될 때마다 다시 생성되지 않도록 한다.

Functional Component 예시

const renderItem = useCallback(({item}) => (
   <View key={item.key}>
      <Text>{item.title}</Text>
   </View>
 ), []);

return (
  // ...

  <FlatList data={items} renderItem={renderItem} />;
  // ...
);

Class Component 예시

renderItem = ({item}) => (<View key={item.key}><Text>{item.title}</Text></View>);

render(){
  // ...

  <FlatList
    data={items}
    renderItem={this.renderItem}
  />

  // ...
}
profile
기록하고 싶은 것을 기록하는 저장소

0개의 댓글