TIL24, React: 1차 프로젝트 4일차, 무한 스크롤

sunghoonKim·2020년 12월 16일
3

오늘의 집 페이지에서 footer를 보려고 스크롤을 내려봤다.


오우 무한 스크롤좀 하는 놈인가? 그럼 질수 없지


react-infinite-scroll-component

무한 스크롤을 구현하려고 여기 저기 알아보다, 해당 기능을 제공하는 라이브러리를 발견하였다. 그 용법을 알아보고, 해당 내용을 내 프로젝트에 적용시켜보자. 설치 및 임포트 과정은 간단하니 생략하겠다.

기본적인 사용법은 아래와 같다.

<InfiniteScroll
  dataLength={items.length}
  next={fetchData}
  hasMore={true}
  loader={<h4>Loading...</h4>}
  endMessage={
    <p style={{ textAlign: 'center' }}>
      <b>Yay! You have seen it all</b>
    </p>
  }
>
  {items}
</InfiniteScroll>

컴포넌트이기 때문에, <InfiniteScroll /> 과 같이 컴포넌트의 형식으로 사용한다. props 로 많은 속성들이 들어가는데, 하나하나 알아보자.

1. dataLength

데이터 배열의 길이 정보가 들어간다. 이 배열 길이 정보는 다음 번 next 함수 호출과 관련이 있다.

2. next

스크롤이 마지막에 닿았을 때, 데이터를 더 받아올 함수가 들어간다.

3. hasMore

next 함수를 더 호출할 지 말지, 그리고 endMessage를 나타낼지 말지에 대한 boolean값이 들어간다. 보통, 불러오는 데이터의 수를 제한 하기 위해 사용된다. 예로, items 의 길이를 추적하면서 특정 수를 넘겼을 시 혹은 더 이상 받아올 데이터가 없을 시, hasMore 의 값을 false로 바꾸어, 더 이상의 무한 스크롤을 멈출 수 있다.

4, Loader

데이터 fetch를 기다리고 있을 때, 나타날 문구가 들어간다.

5, endMessage

스크롤링이 끝났을 때 나타날 문구가 들어간다. hasMore 과 관련이 있다. hasMore 이 false 가 되면, endMessage 가 나타난다.


프로젝트에 적용

위의 용법을 사용하여 프로젝트에 적용해 보았다. 용법이 간단하여, 수월하였다.

한 가지 부분만 수정이 필요했는데, 나의 프로젝트 구조에서는 인피니티 스크롤이 적용될 컴포넌트가 한 단계 더 높은 상위 컴포넌트에서 fetch 받은 데이터를 props로 넘겨받고 있었기 때문에, next 에 담길 함수를 상위 컴포넌트에서 추가로 선언하여 props로 넘겨주어야 했다.

// 상위 컴포넌트
class Community extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      communityCards: [],
      currentIndex: 0,
      NUMBER_OF_ITEMS_TO_FETCH: 12, // 데이터를 한번에 12개씩만 받기로 설정한다.
    };
  }
  
  componentDidMount() {
    this.fetchMoreData();
  }

  // next에 담길 함수
  fetchMoreData = () => {
    fetch(`${API}/data/community/data.json`)
      .then(response => response.json())
      .then(result => {
        const {
          communityCards,
          currentIndex,
          NUMBER_OF_ITEMS_TO_FETCH,
        } = this.state;
        this.setState({
          communityCards: communityCards.concat(
            result.communityCards.slice(
              currentIndex,
              currentIndex + NUMBER_OF_ITEMS_TO_FETCH
            )
          ),
          currentIndex: currentIndex + NUMBER_OF_ITEMS_TO_FETCH,
        });
      });
  };

  render() {
    return (
      <CommunityCardList
        fetchMoreData={this.fetchMoreData} // 해당 함수를 props로 넘긴다.
        communityCards={this.state.communityCards}
        /> 
    );
  }
}



// 하위 컴포넌트
import React from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import CommunityCard from "./CommunityCard";

class CommunityCardList extends React.Component {
  render() {
    const { communityCards } = this.props;
    return (
      <InfiniteScroll
        dataLength={communityCards.length}
        next={this.props.fetchMoreData}
        hasMore={true}
      >
        <div className="CommunityCardGrid">
          {communityCards?.map(communityCard => (
              <CommunityCard communityCard={communityCard} />
            ))}
        </div>
      </InfiniteScroll>
    );
  }
}

코드는 위와 같이 구성된다.

결과물 또한 잘 작동한다!


어찌어찌 때려 맞춰주면 알아서 잘 돌아가주니 고맙네. 장하다 내 코드. 이 기세로 내일 필터링 기능까지 잘 돌아가주라 ^-^

0개의 댓글