React 무한 스크롤 구현

김진원·2023년 12월 7일
0

React

목록 보기
4/4
post-thumbnail

무한 스크롤?

무한 스크롤은 사용자가 스크롤링 시 컨텐츠가 동적으로 생성되는 로드 방식을 의미 합니다.

무한스크롤 목표

무한 스크롤을 구현함으로써, 데이터 로드 방식의 이해를 돕기 위함 입니다.
구현 목표는 다음과 같았습니다.
1. 초기 보여줄 데이터의 개수
2. 스크롤링 시 로드되는 데이터
3. 데이터 로딩 시 로딩 표현
4. 데이터 모두 로드 시 무한 스크롤 중단

직접 구현? 라이브러리?

기존 Js Intersection Observer을 이용해 구현 했던 적이 있습니다.
react로 구현이 목표인만큼, react-infinitescroll-component라는 라이브러리를 사용하여 구현 해보도록 하겠습니다.

Data API - Jsonplaceholder

구현에 필요한 데이터는 유명한 데이터 제공 API인 Jsonplaceholder를 사용 했습니다.
페이지네이션 구현 때와 마찬가지로 먼저 데이터를 불러 오도록 하겠습니다.

const InfinteSection = () => {

    // 마운트 시 데이터 호출 후 저장
    const [data, setData] = useState([]);
    const dataUrl = "https://jsonplaceholder.org/posts";

    const dataGet = async () => {
        try {
            const res = await axios.get(`${dataUrl}`);
    
            setData(res.data);
    
        } catch (err) {
            console.log("error");
        }
    };

    useEffect(()=> {
        dataGet()
        return
    }, []);

    return (
            <Content data={data} /> 
    )
}

불러온 데이터는 무한스크롤을 구현할 Content로 props를 넘겨줍니다.

무한스크롤 구현

먼저 부모 컴포넌트로부터 전달 받은 전체 데이터(props)를 저장할 상태와,
초기 렌더링시 보여줄 데이터 배열(초기 5개)를 useEffect를 사용하여 지정해줍니다. useEffect를 사용하는 이유는 초기 데이터를 비동기로 받아오기 때문입니다.

content.js

    // props로 받은 전체 데이터 배열
    const [scrollImage, setScrollImage] = useState(Image.data);

    // 초기 렌더링 시 보여줄 데이터 배열
    const [imageData, setImageData] = useState(null);
    
    // props와  scrollImage
    useEffect(()=> {
        setScrollImage(Image.data);

        //초기 보여줄 컨텐츠 개수 지정
        const sliceImage = scrollImage.slice(0,4);
        setImageData(sliceImage)

    },[Image, scrollImage]);

다음은 무한스크롤 관련 함수를 작성 해보겠습니다.
npm을 통해 react-infinitescorll-comopnent를 설치 후 import 해줍니다.

import InfiniteScroll from "react-infinite-scroll-component";

hasMore State는 무한스크롤 라이브러리 사용시 데이터를 추가로 로드할지 말지에 대한 상태값입니다.

contentIdx State는 추가로 로드할 데이터의 Index 값입니다. slice와 concat 함수를 사용하여 기존 배열에 자른 배열을 붙이는 형식으로 구현했습니다.

fetchMoreData 함수는 hasMore값이 true일 경우 작동 되는 함수입니다.
contentIdx의 마지막 값이 전체 데이터보다 적을 시 fetchMoreData 함수가 실행되며 추가 로드 될 컨텐츠의 Index값이 업데이트되고 배열을 추가 해줍니다.
hasMorea값이 false일 경우 무한스크롤은 중단 됩니다.

content.js

    // 무한 스크롤 기능 중단 여부
    const [hasMore, setHasMore] = useState(true);

    // 로드 될 컨텐츠 index 배열
    let [contentIdx, setContentIdx] = useState([4,9]);

    // 스크롤링시 함수
    const fetchMoreData= () => {

    // 로드될 컨텐츠의 마지막 index number가 전체 데이터 배열의 length 보다 작을 시 추가 데이터 load
    if ( contentIdx[1] < scrollImage.length) {
        setTimeout(()=> {
            setImageData(imageData.concat(scrollImage.slice(contentIdx[0],contentIdx[1])))
            setContentIdx(prevState => [prevState[0] + 5, prevState[1] + 5])
        }, 700)
    }
    //  무한스크롤 중단
    else {
        setHasMore(false);
    }
}

다음은 return 부분입니다.
여기서 주목 해야할점은 dataLength, next, hasMore입니다.
react-infinitescroll-component가 제공해주는 기능으로서 무한스크롤 구현의 핵심 속성값들입니다. 위 세가지 속성값은 다음을 제공해줍니다.
dataLength = 데이터의 길이를 지정
next = 무한 스크롤시 실행될 함수를 지정
hasMore = 데이터 추가 로드 실행 여부

데이터의 길이는 초기 전체 데이터의 length로 지정해주고 next는 위에 언급된 fetchMoreData 함수를 지정 해줍니다.
무한 스크롤링시 fetchMoreData 함수가 실행되며 데이터를 불러옵니다.

추가적으로 loader, endMessage 속성값을 통해 로딩시, 로드 완료시 화면을 구현할 수 있습니다.

content.js

    return (
      <>
        {imageData && (
            <Wrap id="parentScroll">
                <InfiniteScroll 
                    dataLength={imageData.length} 
                    next={fetchMoreData} 
                    hasMore={hasMore} 
                    loader={<Loading>Loading...</Loading>} 
                    endMessage={<p>Do not load data</p>}
                    scrollableTarget="parentScroll"
                    height={350}
                >
                    {imageData.map((item, idx)=> {
                        return (
                            <ContentBox key={item.id}>
                                <img style={{width:"100%"}} src={item.image} alt="content image"></img>
                                <h3>{item.title}</h3>
                            </ContentBox>
                        )
                    })} 
                </InfiniteScroll>
            </Wrap>
        )}
      </>

    )

위의 방식으로 구현된 화면입니다.

무한스크롤을 구현하면서...

SNS 등에서 가장 많이 쓰이는 로드방식으로서 제작 목표중인 Question이라는 SNS 프로젝트에도 사용될 것 같아 구현을 해보았습니다.

앞서 페이지네이션을 구현해봄으로써, 비슷한 로직이 많이 쓰인다고 느꼈고 한결 수월하게 원하던 목표를 다 구현해낼 수 있었습니다.

데이터 로드와 concat함수 등의 이해를 가질 수 있었습니다.

자세한 코드는 아래를 참고 해주세요.

전체 코드
[github]
https://github.com/rlawlsdnjs/react_infinite_scroll.git

profile
사용자의 관점에 대해 욕심이 많은 개발자

0개의 댓글