React Native

react naitve 무한 스크롤, 페이지 네이션 구현하기 ( scrollview, flatList )

B_Tae 2023. 8. 17. 23:06

무한스크롤, 페이지네이션이란?


무한스크롤, 페이지네이션이란?

무한 스크롤과 페이지네이션은 비록 방식이 다르지만, 비슷한 목적을 가진 기법이다.

페이지네이션과 무한 스크롤은 데이터를 효과적으로 표현하기 위한 한 가지 기법이다. 한 번에 많은 양의 데이터를 받게 될 경우, 받는 과정이 오래 걸리고 그 데이터를 기반으로 UI를 그리는 데도 시간이 소요된다. 따라서 먼저 데이터를 일부만 불러온 후, 특정 이벤트가 발생할 때 추가 데이터를 받을 수 있다. 페이지네이션의 경우, 흔히 검색에서 볼 수 있는 '이전', '다음'과 페이지 번호를 누를 때 다음 데이터를 로드하게 된다. 반면, 무한 스크롤의 경우 개발자가 지정한 높이를 지나 스크롤했을 때 이벤트를 설정해 추가 데이터를 로드할 수 있다.

일반적으로 페이지네이션은 PC나 순서가 중요한 게시물에서 사용하며, 무한 스크롤은 모바일 또는 순서에 제한이 없는 경우 사용하는 것이 좋다고 생각합니다.

비동기 통신 방법 (코드)

무한스크롤과 페이지네이션에 공통점은 데이터를 일정 갯수로 나누어 페이지처럼 분류할 수 있다는 것이다. 따라서 불러오는 통신관련 코드는 유사하다. 아래는 방금 작성한 예시입니다.


  const [page, setPage] = useState(0);
  const [datas, setDatas] = useState([]);
  const [isEndPage, setIsEndPage] = useState(false);

  useEffect(() => {
    pageNation(page);
  }, [page]);

  const pageNation = async (page) => {
    if (isEndPage) return; //다음 페이지가 없으면 종료
    const { data, success } = await getPageNationApi(page);

    if (success) {
      setDatas(data.list);
      setIsEndPage(data.isEndPage); // 마지막 페이지
    }
  };

해당 통신에는 서버 코드가 중요합니다. 사용자가 원하는 페이지를 받아 해당 페이지를 보내주면된다. 구현 설계에 따라 다르지만 마지막 페이지를 알아야 불필요한 요청을 안할 수 있다. 내가 구현했었던 기억으로는 list, isEndPage, totalPage, nowPage 이렇게 받았었습니다.

무한 스크롤

무한 스크롤은 앞서 말했듯 스크롤을 내리며 특정 지점이 지났을 때 요청을 보내는 방식입니다. react-native에서 scroll을 구현하기 위한 태그로는 ScrollView,FlatList 방식이 있습니다. (두 태그에 차이는 따로 정리하지 않겠습니다.)

ScrollView

    const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize,}: NativeScrollEvent) => {
        const paddingToBottom = 20;

          return (
            layoutMeasurement.height + contentOffset.y >=
            contentSize.height - paddingToBottom
          );
    };

    retrun(
     <ScrollView
        contentContainerStyle={{ width: '100%' }}
        onScrollEndDrag={({ nativeEvent }) => {
          if (isCloseToBottom(nativeEvent) && !isEndPage ) {
            setPage((page)=> page + 1)
          }
        }}
        scrollEventThrottle={200}
      >
        // ... header

        {datas.map((data) => <Component key={data.id} data={data}} />

        // ... footer
      </ScrollView>
    )

ScrollView에서는 onScrollEndDrag이벤트를 이용합니다. 스크롤 후 손이 떨어질 때 해당 콜백 함수가 실행됩니다. scrollEventThrottle는 스크롤 이벤트에 Throttle를 걸 수있습니다. 단위는 "ms"이며 작을 경우 많은 이벤트가 발생할 수 있으며 너무 길 경우 이벤트를 호출하여 새로운 List를 불어오는게 늦어져 사용자에 만족도가 떨어질 수 있습니다. 실제 테스트해보며 적정한 속도를 찾을 필요가 있습니다.

isCloseToBottom 함수를 살펴보면 매개변수로 현재 스크롤 위치에 대한 정보를 받게됩니다. layoutMeasurement.height은 기기 화면 높이, contentOffset.y 스크롤 y축 높이(화면에 상단 기준) ScrollView 전체 높이를 나타냅니다. 따라서 현재 화면 하단에 높이가 전체 높이 - (사용자가 정하는 높이)보다 클 경우 다음 페이지를 로드하게 됩니다.

FlatList

    <FlatList
        data={datas}
        keyExtractor={(data) => data.id}
        renderItem={({ data }) => (
         <Component data={data} />
        )}
        ListHeaderComponent={
         // ...header
        }
        ListFooterComponent={() => (
         // ...footer
        )}
        onEndReached={() => setPage(page + 1)}
          onEndReachedThreshold={0.7}
          contentContainerStyle={{width : '100%}}
      />
    </View>

FlatList에서는 onEndReached,onEndReachedThreshold를 이용하여 무한스크롤을 구현할 수 있습니다. onEndReached는 지정된 높이를 지날 때 콜백함수를 실행합니다. onEndReachedThreshold는 높이를 지정할 수 있습니다. 0일 경우 스크롤 최하단 커질수록 지점이 높아집니다. (1로 설정했을 때 최하단 + 화면 높이에서 이벤트가 발생됩니다)
즉 위 코드는 최하단 기준으로 화면 크기에 70%지점을 통과할 때 이벤트가 발생하며 Page를 변경하여 새로운 List를 로드합니다.

무한 스크롤 추가 구현 사항 및 ScrollView, FlatList 장단점

  • 이벤트 지점은 대개 최하단보다 위
    위 코드를 보면 특정 지점이 최하단이 아닌 것을 볼 수 있습니다. 이유는 간단하죠. 사용자 입장에서 다음 컨텐츠를 기다리는 시간이 발생하는 것을 좋아하지 않습니다텍스트. 그래서 사용자가 컨텐츠 마지막을 보기 전에 다음 컨텐츠를 미리 불러와야합니다. 시점은 상황에 따라 달라질 것 같습니다. 불러오는 속도가 느리거나 빠르게 스크롤이 되는 컨텐츠라면 더 빨리 이벤트를 발생해야할 것입니다.


  • 진행중과 마지막 페이지 상태를 표시하자
    사용자 입장에서 더 이상 컨텐츠가 없는지 불러오고 있는 중인지 모를 경우 이탈율이 높아집니다. 스크롤 속도를 고려하여 구현했지만 모든 사용자가 해당되지 않기 때문에 현재 어떤 상태인지 컨텐츠 하단에 인디케이터 등을 이용하여 표시할 필요가 있습니다.

  • 장 단점
    ScrollView 장점
    ScrollView는 다양한 상황에서 사용하는 만큼 익숙하기에 새로운 학습이 필요없다.
    기존 ScrollView로 구현한 컴포넌트에 사용할 수 있다.

    ScrollView 단점
    스크롤이 끝난 후 이벤트가 발생하기 때문에 빠르게 스크롤을 내릴 때 어색한 느낌이 있다.
    특정 지점 이후 모든 스크롤에 이벤트가 발생하기 때문에 중복 요청이 발생할 수 있다.

**FlatList 장점**
많은 데이터를 보이는데 ScrollView보다 빠르다. 
구현이 쉽다.
ScrollView는 특정 지점 이후 모든 스크롤에 이벤트가 발생하는 반면에 FlatList는 특정 지점을 지나는 순간에만 이벤트가 발생하기 때문에 요청 수를 관리하기 편하다.

**FlatList 단점**
ScrollView로 구현된 컴포넌트에 사용하려면 FlatList로 변경하는데 비용이 든다.

전반적으로 FlatList 사용에 제한이 있는게 아니라면 FlatList를 사용하는게 바람직할 것 같습니다.

페이지 네이션

무한 스크롤은 스크롤 이벤트를 이용했다면, 페이지 네이션은 단순히 버튼을 누르는 click, press 이벤트를 이용한다. 고로 많이 쉽다.

페이지를 나타내는 버튼을 눌르면 해당 페이지에 관한 컨텐츠를 받아오기만 하면 됩니다. 무한 스크롤은 스크롤에 따라 다수에 컨텐츠를 보여야 하는 경우가 있어 성능 등 신경써야하는 부분이 많지만, 페이지 네이션에 경우 정해진 갯수에 컨텐츠만 보이기 때문에 FlatList보다는 ScrollView를 이용해서 간편하게 구현해도 좋을 것 같습니다.

코드로는 따로 작성하지 않겠습니다.

PS.

무한 스크롤과 페이지 네이션에 대해 정리해봤습니다. 웹/앱에서 꼭 사용하는 기술인 것 같고 난이도도 크게 어렵지 않은 기능입니다. 이 포스트가 많은 도움이 되셨으면 좋겠습니다. 거친 피드백은 항상 환영이며 궁금하신건 남겨주시면 답변드리도록 하겠습니다.

참고

react-native Docs