Kimsora✨
320x100
반응형

Intersection Observer의 필요성

  • 페이지 스크롤 시 이미지를 Lazy-loading(지연 로딩)할 때
  • Infinite scrolling(무한 스크롤)을 통해 스크롤할 때 새로운 콘텐츠를 불러올 때
  • 광고의 수익을 계산하기 위해 광고의 가시성을 참고할 때
  • 사용자가 결과를 볼 것인지에 따라 애니메이션 동작 여부를 결정할 때

=>브라우저 뷰포트(Viewport)와 설정한 요소(Element)의 교차점을 관찰하며, 요소가 뷰포트에 포함되는지 포함되지 않는지, 더 쉽게는 사용자 화면에 지금 보이는 요소인지 아닌지를 구별하는 기능을 제공한다

scroll 이벤트와 다르게 교차 시 비동기적으로 실행되며 가시성 구분 시 reflow 를 발생하지 않는다

Intersection Observer 사용 방법

// 기본구조는 콜백함수와 옵션을 받는다.
const io = new IntersectionObserver(callback[, options])

new 키워드를 통해 인스턴스를 생성하고 . callback , options 2개의 파라미터를 받는다

Parameters

callback

 

Entries

entries 는 IntersectionObserverEntry 인스턴스를 담은 배열이다. 일반적으로 callback 에 파라미터로 전달이 되고 Intersection Observer.takeRecords() 를 통해 반환받을 수도 있다.

IntersectionObserverEntry 는 루트요소와 타겟요소의 교차(threshold 와 만났을 때)의 상황을 묘사합니다. 포함된 프로퍼티들은 모두 읽기전용(read only) 이다

  • IntersectionObserverEntry.boundingClientRect : 타겟 요소의 사각형 정보(DOMRectReadOnly)를 반환한다. getBoundingClientRect() 호출과는 다르게 reflow 를 발생시키진 않는다.
  • IntersectionObserverEntry.intersectionRect : 타겟 요소의 가시성이 감지된 부분의 정보(DOMRectReadOnly)를 반환한다.
  • IntersectionObserverEntry.intersectionRatio : 타겟 요소의 intersectionRect 이 boundingClientRect 와 어느정도로 교차(겹치는 지) 비율(0.0 ~ 1.0)을 반환한다 ( 타겟 요소가 루트 요소와 얼마나 교차하는지의 정도와 같다)

Methods

  • IntersectionObserver.observe(targetElement) : 타겟 요소에 대한 관찰을 시작
  • IntersectionObserver.unobserve(targetElement) : 타겟 요소에 대한 관찰을 중지. 관찰의 목적이 이루어져 굳이 계속 관찰을 할 필요가 없는 경우 사용.
  • IntersectionObserver.disconnect() : 인스턴스의 타겟 요소들에 대한 모든 관찰을 중지.
  • IntersectionObserver.takerecords(targetElement) : IntersectionObserverEntry 인스턴스들의 배열을 리턴.

 

options

root
타겟 요소의 가시성을 확인할 때 사용되는 루트 요소입니다. 이것은 타겟 요소보다 상위 요소,요소의 조상 요소여야 한다

설정하지 않거나 root 값을 null 로 주었을 때 기본 값으로 브라우저 뷰포트가 설정됩니다.

 

rootMargin
margin 을 주어 루트 요소의 범위를 확장할 수 있다. 즉 확장된 영역 안에 타겟 요소가 들어가면 가시성에 변화가 생긴다 CSS 의 margin 과 유사하게 toprightbottomleft 의 margin 정도롤 각각 설정할 수 있다. 기본 값은 0이며 따로 설정 시 단위를 꼭 입력해야한다

 

threshold
콜백이 실행될 타겟 요소의 가시성 퍼센티지를 나타내는 단일 숫자 및 숫자 배열이 들어갈 수 있다.  요소의 topbottom 이 노출된 순간만 콜백을 실행할 수 있는 것이 아니라 어느정도 타겟 요소가 보여졌는 지에 따라서도 콜백을 호출할 수 있다. 예를 들어 요소가 50%만큼 보여졌을 때 탐지하고 싶다면 단일 숫자 값 0.5 를 설정하면 된다. 혹은 25% 단위로 가시성이 변경될 때마다 콜백이 실행되게 하고 싶다면 [0, 0.25, 0.5, 0.75, 1] 을 설정하면 된다.

🥲무한 스크롤 구현하기

아직 완벽한 이해를 못했지만...  다시 코드를 뜯어 볼것🙂

 

데이터 패칭하기

  • fetch함수를 이용해서 데이터를 불러오는 함수 를 만들어준다. 무한 스크롤을 구현하기 위해서는 데이터를 처음부터 계속 보여줘야하기 때문에 데이터를 담고 있는 state인 movie 를 operator연산자로 복제한다
  • 스크롤이 닿았을 때 새롭게 데이터 페이지를 바꾸는 state인 page를 만들어준다. 그리고 useEffect로 page의 넘버가 바뀔 때마다 movieHandler함수를 호출시킨다.
 
  const [movie, setMovie] = useState([]);
  const [page, setPage] = useState(1); //스크롤이 닿았을 때 새롭게 데이터 페이지를 바꿀 state
  const [loading, setLoading] = useState(false); //로딩 성공, 실패를 담을 state

  const movieHandler = (page) => {
    axios
      .get(`https://yts.mx/api/v2/list_movies.json?page=${page}&limit=3`)
      .then((res) => {
        setMovie((pre) => [...pre, ...res.data.data.movies]);
        setLoading(true);
      });
  };

page넘버를 바꾸는 함수 만들기

  • movieHandler를 실행시켜 데이터를 불러오고  page를 1씩 증가시켜서 그 다음 데이터를 불러오도록 한다. 새롭게 불러와진 데이터는 movieHandler를 통해서 기존에 있던 데이터에 더해지게 된다.
  • loadMore함수를 만들어서 page가 1씩 더해지는 함수를 만든다
useEffect(() => {
    movieHandler(page);
  }, [page]);

 useRef를 사용한 target설정하기

무한 스크롤은 마지막 엘리먼트에 닿았을 때 데이터를 자동으로 불러온다. 이 페이지의 마지막 요소는 <div><div/> 이기 때문에 여기에 ref를 지정해놓고 탐색 타겟으로 설정한다.

=> <div></div>에 도달했을 때 데이터 패칭이 된다

return (
    <ul className={classes["movies-list"]}>
      {props?.movies.map((movie) => (
        <Movie
          key={v4()}
          title={movie?.title}
          releaseDate={movie?.openDt}
          openingText={movie?.summary}
          rating={movie.rating}
        />
      ))}
      <div ref={pageEnd}></div>
    </ul>
  );
};

 Intersection Observer를 사용해서 뷰포트 안에 있는 요소 확인하기

  • Intersection Observer를 통해서 뷰포트 내에 지정해둔 타겟 div를 찾고 있으면, loadMore함수를 실행시켜 page를 1씩 증가 시킨다
const MovieList = (props) => {
  const pageEnd = useRef();
  useEffect(() => {
    if (props.loading) {
      //로딩되었을 때만 실행
      const observer = new IntersectionObserver(
        (entries) => {
          if (entries[0].isIntersecting) {
            props.handle();
          }
        },
        { threshold: 1 }
      );
      //옵져버 탐색 시작
      observer.observe(pageEnd.current);
    }
  }, [props.loading]);

 

 

참고 사이트:https://velog.io/@ahn-sujin/ReactIntersection-Observer-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-%EB%AC%B4%ED%95%9C%EC%8A%A4%ED%81%AC%EB%A1%A4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

728x90
반응형

'React' 카테고리의 다른 글

페이지네이션 커서기반과 오프셋기반  (0) 2023.01.16
useEffect 와 useLayoutEffect  (0) 2023.01.15
redux persist  (0) 2022.12.19
redux-toolkit  (0) 2022.12.19
Fragment/Portal  (0) 2022.12.04
profile

Kimsora✨

@sorarar

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그

WH