무한 스크롤 훅 만들기

13696 단어 reactjavascript
모바일 앱을 사용해 본 적이 있다면 무한 두루마리를 만났을 가능성이 높습니다. 기본적으로 스크롤하면 주어진 DOM 높이에서 무언가가 발생합니다. 예를 들어 Twitter는 사용자가 맨 아래에 도달하면 새 게시물을 가져옵니다.

Hooks는 React의 게임 체인저였습니다. 이제 Functional Components는 상태 및 수명 주기 메서드를 가질 수 있습니다. 사용자 정의 후크를 재사용하여 요소에 동작을 추가할 수도 있습니다. 이는 결국 HOC 및 "Wrapper Hell"에 대한 좋은 대안입니다. 그래서 오늘은 이 기능을 구현하기 위해 React Hook을 만드는 방법을 알려 드리겠습니다.

갑시다!



이 후크가 무엇을 해야 하는지 정의하는 것으로 시작하겠습니다. 따라서 가장 먼저 할 일은 이벤트 리스너를 window 에 추가하는 것입니다. 왜냐하면 우리는 scrollHeight 를 감시할 것이기 때문에 다음과 같습니다.

import { useEffect, useState } from 'react';

const useInfiniteScroll = (callback: Function) => {
  useEffect(() => {
    window.addEventListener('scroll', callback);
    return () => window.removeEventListener('scroll', callback);
  });
}


임계값



이제 callback 함수는 원하는 동작이 아닌 페이지가 스크롤될 때마다 호출됩니다. 따라서 교차한 후 트리거될 임계값을 추가해야 합니다. 이것은 매개변수를 통해 제공되며 값은 0과 1 사이여야 합니다.

import { useEffect, useState } from 'react';

const useInfiniteScroll = (callback: Function, threshold: number = 1) => {
  useEffect(() => {
    const handleScroll = () => {
      if (window.innerHeight + document.documentElement.scrollTop 
        >= document.documentElement.offsetHeight * threshold) 
          callback();
    };
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [callback]);
}


이상한 버그



핵심은 기본적으로 완료됩니다. 그러나 "트리거 포인트"를 넘어 계속 스크롤하면 callback가 여러 번 호출되고 있음을 알 수 있습니다. 이 스크롤 높이 이후에 호출되고 한 번만 발생하도록 보장해야 하기 때문에 발생합니다. 이렇게 하려면 isFetching를 추가할 수 있습니다.

import { useEffect, useState } from 'react';

const useInfiniteScroll = (callback: Function, threshold: number = 1) => {
  const [isFetching, setIsFetching] = useState<Boolean>(false);

  useEffect(() => {
    const handleScroll = () => {
      if (window.innerHeight + document.documentElement.scrollTop 
        >= document.documentElement.offsetHeight * threshold
        && !isFetching) {
          setIsFetching(true);
          callback();
        }
    };
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [isFetching, callback]);

  return [setIsFetching];
}


콜백이 가져오기를 완료했는지 여부를 제어할 수 있도록 setIsFetching를 반환할 것입니다.

마지막으로 중요한 것은



대부분의 경우 무한 스크롤은 실제로 무한이 아닙니다. 따라서 더 이상 가져올 데이터가 없으면 이벤트 리스너가 더 이상 필요하지 않으므로 제거하는 것이 좋습니다.

import { useEffect, useState } from 'react';

const useInfiniteScroll = (callback: Function, threshold: number = 1) => {
    const [isFetching, setIsFetching] = useState<Boolean>(false);
    const [isExhausted, setIsExhausted] = useState<Boolean>(false);

  useEffect(() => {
    const handleScroll = () => {
      if (window.innerHeight + document.documentElement.scrollTop 
        >= document.documentElement.offsetHeight * threshold
        && !isFetching) {
          setIsFetching(true);
          callback();
        }
    };
    if (isExhausted) window.removeEventListener('scroll', handleScroll);
    else window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [isFetching, isExhausted, callback]);

  return [setIsFetching, isExhausted, setIsExhausted];
}


이제 isExhaustedsetIsExhausted 도 반환됩니다. 첫 번째는 메시지를 렌더링하는 데 사용할 수 있고 두 번째는 가져올 데이터가 더 이상 없다고 후크에 알릴 수 있습니다.

그게 다야



그게 다야, 얘들아. 이 기능을 구현하는 방법을 알려드릴 수 있기를 바랍니다. 이 접근 방식은 가장 화려하지 않더라도 저에게 매력으로 작용했습니다.

추신: 표지는 Alon Sivan의 "How To Love - Three easy steps"에서 가져왔습니다.

좋은 웹페이지 즐겨찾기