[React] 무한 스크롤 - 기본편

Pulan·2022년 8월 14일
0
post-thumbnail

무한 스크롤은 어떻게 구현해야 되는가?

  1. 스크롤을 통해 컨텐츠의 끝 부분을 감지한다.
  2. 다음에 나올 컨텐츠들을 불러와 현재 페이지에 붙인다.

과정

  1. state 설정
    • postList: 배열안에 객체의 형태를 가진 데이터를 넣는다.
    • items: 현재 가져올 데이터의 개수를 정한다.
    • prevItems: 이전에 가졌던 데이터의 개수
const [postData, setPostData] = useState({
    postList: [],
    items: 5,
    prevItems: 0,
  });
  1. 지정한 개수에 맞는 데이터 가져오기
    • 최초 렌더링시 가져올 데이터의 개수는 5개로 잡는다.
    • slice 메서드를 이용해서 0 ~ 5개의 데이터를 Mock 데이터에서 가져와서 sliceData 변수에 저장한다.
    • postData에 들어있는 postList에 sliceData를 적용한다.
  useEffect(() => {
    const checkStatus = res => {
      if (!res.ok) throw new Error(`Again Check Status: ${res.status}`);
      return res.json();
    };
    const uploadPostData = data => {
      const { postList, preItems, items } = postData;
      const sliceData = data.slice(preItems, items);
      setPostData({ ...postData, postList: [...postList, ...sliceData] });
    };
    const getPosts = url =>
      fetch(url, {
        method: 'GET',
      });

    getPosts('/data/post.json')
      .then(checkStatus)
      .then(uploadPostData)
      .catch(error => console.error(error));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [postData.items]);
  1. 스크롤이 끝나기 직전에 새로운 데이터 가져오기
    Element size and scrolling 참고
    • document.documentElement을 이용하여 geometry property(기하 프로퍼티)에 접근해서 우리가 필요한 속성을 가져온다. (scrollTop, clientHeight, scrollHeight)
    • 가져온 속성을 이용해서 데이터를 가지고 온 뒤에도 높이를 계산할 수 있게 만든다. (scrollRatio)
    • 브라우저나 기기마다 차이가 있을 수 있어서 0.95 값을 적용하여 보다 더 자연스럽게 해준다.
    • 밑에 코드에서 Math.max 함수가 있는데 이건 사이트 전체를 컨트롤하는거라면 document.documentElement의 값만을 참조하는 것은 위험할 수 있다고 해서 좀 더 정확하게 하기 위해서 body에 담겨있는 geometry값과 비교해서 가장 큰 값으로 사용했다.
  const onScroll = () => {
    const { items } = postData;
    const { documentElement, body } = document;

    const scrollTop = Math.max(documentElement.scrollTop, body.scrollTop);
    const clientHeight = documentElement.clientHeight;
    const scrollHeight = Math.max(
      documentElement.scrollHeight,
      body.scrollHeight
    );

    const scrollRatio = (scrollTop + clientHeight) / scrollHeight;

    if (scrollRatio > 0.95) {
      setPostData({ ...postData, items: items + 5, preItems: items });
    }
  };

  useEffect(() => {
    window.addEventListener('scroll', onScroll);

    return () => {
      window.removeEventListener('scroll', onScroll);
    };
  }, [onScroll]);
profile
현재 개발 중인 블로그로 내용들을 개선하면서 업데이트하고 있습니다. https://www.plu457.life/

0개의 댓글