본문 바로가기

공부 정리

23.08.23 : React Native - FlatList로 Infinite Scroll 구현하기

반응형

안녕하세요 FE 개발자 노은지입니다.

React Native로 어플리케이션을 만들때, 효율적으로 List를 렌더링 할 수 있는 RN의 내장 컴포넌트인 FlatList에 대해서 알아보고, 무한 스크롤을 적용하는 방법을 공부 해보았습니다.

 

FlatList

기본적인 리스트를 렌더링을 하기 위하여 편리한 여러 기능을 지원하는 고성능 인터페이스로 다음과 같은 기능을 제공합니다.

 

1. Fully cross-platform

웹, 모바일(iOS 및 Android)등 여러 플랫폼에서 완벽하게 작동

 

2. Optional horizontal mode

horizontal prop 이용해 수평 스크롤 모드 지원

 

3. Configurable viewability callbacks

onEndReached, onEndReachedThreshold prop 이용하여 화면에 새로운 항목이 나타났을 때, 특정 함수를 호출해 추가 작업을 수행

 

4. Hearder support

ListHeaderComponent prop으로 리스트의 최상단에 고정되는 헤더 섹션 추가 가능

 

5. Footer support

ListFooterComponent prop 이용해 리스트 최하단 고정되는 푸터 컴포넌트 추가 가능

 

6. Separator support

ItemSeparatorComponent prop 이용해 separator 추가 가능

 

7. Pull to Refresh

사용자가 리스트를 아래로 당겨 새로고침 하려고 할때 발생하는 기능. refreshing, onRefresh prop 사용

 

8. Scroll loading

무한 스크롤기능. 사용자가 리스트를 스크롤할 대 추가 데이터를 동적으로 로드, 스크롤이 끝에 도달할 때마다 새로운 항목을 자동으로 로드함. onEndReached, onEndReachedThreshold prop 이용

 

9. ScrollToIndex support

scrollToIndex 메서드를 통해 특정 항목으로 스크롤하는 기능을 지원. 이를 통해서 특정 항목이나 인덱스로 스크롤이 가능함. (FlatList의 ref를 사용해서 호출)

 

20. Multiple column support

numColumns prop으로 multiple column 가능

 

 

FlatList의 필수 props

 

renderItem (Required)

data prop으로 전달받은 data의 item을 리스트에 렌더링시키는 역할을 합니다. 

renderItem의 함수가 PureComponent 또는 memoized 컴포넌트로 만들어지면 성능 최적화에 도움이 될 수 있으므로 memoize를 사용하는 것이 권장됩니다. 

data (Required)

렌더링 할 item array (또는 array-like list)

 

 

FlatList로 무한 스크롤 구현하기

 

atomic pattern으로 개발을 진행하면서 컴포넌트를 최소 단위인 atom으로 쪼개고, atom이 2개 이상으로 구성 되어있는 molecules 단위까지 설계했는데요, 그 중 하나인 <ImageCard/> component는 다음과 같은 모습을 하고 있는 molecule입니다.

 

 

이 molecule은 리스트를 구성하게 될 컴포넌트이기 때문에 storybook 상에서 볼 수 있게끔 mock data를 이용해 무한스크롤을 구현했습니다.

 

import React, { useState } from 'react';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { ImageCard } from 'src/components/molecule';
import { FlatList, TouchableOpacity } from 'react-native';
import { Flexbox } from 'src/components/atom';

export default {
  title: 'ImageCard',
  component: ImageCard,
} as ComponentMeta<typeof ImageCard>;

const Template: ComponentStory<typeof ImageCard> = (args) => {
  const DATA = [
    {
      desc: '서울 천왕동',
      title: '커스텀 키보드',
      src: 'https://img.danawa.com/images/descFiles/6/68/5067243_CxXEIN2WXm_1654690609267.jpeg',
    },
    {
      desc: '서울 화양동',
      title: '맑은 공기 리조트',
      src: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTF9G-UFAbO7tFzELzAxyOETOskVhZv88S7wg&usqp=CAU',
    },

   ...생략...

  ];

  // 현재 페이지를 상태로 관리
  const [currentPage, setCurrentPage] = useState(1);

  // 각 페이지의 데이터를 정의
  const itemsPerPage = 6;
  const totalPages = Math.ceil(DATA.length / itemsPerPage);

  // 데이터 필터링
  const currentData = DATA.slice(0, currentPage * itemsPerPage);

  // 다음 페이지로 이동하는 함수
  const loadMoreData = () => {
    if (currentPage < totalPages) {
      setCurrentPage(currentPage + 1);
    }
  };

  const renderItem = React.useCallback(
    ({ item }) => (
      <Flexbox.Item flex={1}>
        <ImageCard {...item} {...args} />
      </Flexbox.Item>
    ),
    [args] // 필요한 의존성을 배열에 명시
  );

  return (
    <Flexbox>
      <Flexbox.Item height={600} width={'100%'}>
        <FlatList
          data={currentData}
          renderItem={renderItem}
          keyExtractor={(item) => item.src}
          numColumns={2}
          onEndReached={loadMoreData} // 끝에 도달하면 데이터 더 불러오기
          onEndReachedThreshold={0.1} // 끝에 도달하기 전에 호출할 위치 (0.1은 10% 지점)
          columnWrapperStyle={{
            gap: 10,
          }}
        />
      </Flexbox.Item>
    </Flexbox>
  );
};

export const story = Template.bind({});

story.storyName = 'default';
story.args = {
  width: '100%',
  height: 150,
  resizeMode: 'cover',
  onClickHandler: () => {
    window.alert('clicked');
  },
};

 

 

 

React.useCallback을 사용하여 renderItem 함수를 메모이제이션하고 필요한 의존성 배열에 args를 포함시켰기 때문에, args가 변경될 때만 renderItem 함수가 다시 생성됩니다.

이제 FlatList의 renderItem prop으로 renderItem 함수를 전달하여 이미지 카드를 렌더링하게 됩니다. 또한 onEndReached를 통해 스크롤이 끝에 도달하면 데이터를 더 불러오도록 설정되어 있습니다.

 

 

 

Reference : React Native - FlatList

반응형