개발관련/리액트

리액트 컴포넌트 무한 스크롤 구현

개발자 Dane 2023. 5. 11. 19:57
반응형

무한 스크롤 컴포넌트

import React, { useState, useEffect, useRef, FC } from "react";

interface Props {
  fetchData: () => Promise<void>;
  children: React.ReactNode;
}

const InfiniteScroll: FC<Props> = ({ fetchData, children }) => {
  const [isLoading, setIsLoading] = useState(true);
  const loader = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting) {
          setIsLoading(true);
          fetchData().then((newItems) => {
            setIsLoading(false);
          });
        }
      },
      { threshold: 1 }
    );

    if (loader.current) {
      observer.observe(loader.current);
    }

    return () => {
      observer.disconnect();
    };
  }, [loader, setIsLoading, fetchData]);

  return (
    <div>
      {children}
      <div ref={loader}>
        {isLoading && "로딩..."}
      </div>
    </div>
  );
};

export default InfiniteScroll;

사용법

export const List: React.FC = () => {
  const [page, setPage] = useState(1);
  const [list,setList] = React.useState([])
  const fetchData = async () => {
    const response = await axios.get(`https://api.example.com/data?page=${page}&limit=10`);
    setList(prevData => [...prevData, ...response.data]);
  };
  
  return (
    <InfiniteScroll fetchData={fetchData}>
      <ul>
        {list.map((item,i) => (
          <li key={i}>item</li>
        ))}
      </ul>
    </InfiniteScroll>
  );
};

해설

  1. InfiniteScroll 컴포넌트를 만들어서 재사용 가능하게 합니다.
  2. 재사용성을 높이기 위해서 로딩 상태와 UI를 InfiniteScroll내부에 구현합니다.
  3. 데이터를 저장할 data 상태와 페이지 번호를 저장할 page 상태를 생성합니다.
  4. 페이지 번호가 변경될 때마다 API를 호출하여 데이터를 가져옵니다. 가져온 데이터는 이전 데이터와 합쳐집니다.
  5. Intersection Observer를 설정하여 로딩 요소가 뷰포트와 교차할 때마다 페이지 번호를 증가시킵니다.
  6. 로딩 요소에 ref를 설정하여 Intersection Observer가 관찰할 수 있도록 합니다.
반응형