시작하는 중

Intersection observer API를 통한 무한 스크롤 본문

자바스크립트/정리

Intersection observer API를 통한 무한 스크롤

싱욱 2022. 11. 3. 23:52

https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

 

Intersection Observer API - Web APIs | MDN

The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.

developer.mozilla.org

 

이게 뭐냐면 요소 하나를 관찰하도록 설정하고 이 요소가 지정해준 root를 기준으로 얼마나 교차하는가에 따른 threshold를 기준으로 callback 함수를 실행시키는 것이다.

 

let options = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '0px',
  threshold: 1.0
}

let observer = new IntersectionObserver(callback, options);

 

WDN의 코드인데 options에서 기준들을 설정해줄 수 있다.

root는 보통 null을 통해서 viewport로 설정해준다.

rootMargin은 시작점을 안쪽을 향해서 주는 것? 그니깐 Intersection observer의 인식할 사각형을 줄이는 것이다.

threshold는 변화를 관찰할 시점이다. 1.0은 100%이고 Array도 들어갈 수 있다.

 

그렇게 IntersectionObserver의 새로운 인스턴스인 observer를 생성

 

let target = document.querySelector('#listItem');
observer.observe(target);

 

그 다음 querySelector를 통해서 관찰할 요소를 선택해야한다.

그리고 이건 하나의 옵저버가 여러 객체를 관찰할 수 있다.

let target1 = document.querySelector('#listItem1')
let target2 = document.querySelector('#listItem2')
observer.observe(target1)
observer.observe(target2)

이렇게가 가능한거임

 

그리고 중요한 것! 내가 많이 헤맨 부분인데 observer.observe(target)를 통해 실행하게 되면 무조건적으로 callback함수가 실행된다.. 이게 왜 중요하냐면 뒤에 서술하겠음.

 

let callback = (entries, observer) => {
  entries.forEach((entry) => {
    // Each entry describes an intersection change for one observed
    // target element:
    //   entry.boundingClientRect
    //   entry.intersectionRatio
    //   entry.intersectionRect
    //   entry.isIntersecting
    //   entry.rootBounds
    //   entry.target
    //   entry.time
  });
};

콜백함수는 이렇게 쓴다.

우선 console.log를 통해서 저 안의 것들은 어떤 데이터를 갖고 있는지를 꼭 알아야한다.

이는 모든 API를 이용함에 있어서 항상 필요한 것인 것을 오늘 알았다. 타인이 정리해둔 것도 소중하지만 그 분만의 언어로 그 분이 중요하다 생각한 것만 정리했기에 모든 것을 내포하고 있지는 않기에 문서를 꼭 읽어야한다.

 

아무튼 돌아와서 우선 console.log를 찍어봐야한다

let callback = (entries, observer) => {
  console.log(entries)
  console.log(observer)
}

이게 위에서 말한 observe함수 실행시 나타나는 건데 무조건 적으로 callback함수가 실행된다. 그래서 바로 받아오면 우리의 Javascript는 axios든 뭐든 파일을 요청해서 받아오게된다..

그래서 다른 점을 천천히 찾아봤다.

 

드래그한 부분은 단순하게 observe를 실행함으로써 무조건적으로 실행된 callback 함수에 대한 entries와 observer이고

중간 부분은 observer를 출력한 것이라 지금 중요하진 않고

밑의 부분은 실제로 observer가 viewport를 기준으로 나타나서 callback함수가 실행된 것이다.

 

차이점은 isIntersecting이다..

그래서 callback함수에 해당 속성에 접근하여 true일 경우에 원하는 함수를 실행해야하는 것이다.

이걸 알고서 callback함수 구조를 어떻게 잡았냐면

let callback = (entries, observer) => {
  entries.forEach((entry) => {
 	if (entry.isIntersecting === true) {
      // 파일 추가 로드
    }
  })
}

식으로 짰다.

 

그러면 observer를 어떤 요소에 잡아야하는 가도 생각해야한다.

 

보통 구조마다 다르겠지만 마지막 요소가 좋다고 생각한다.

1. html을 건드릴 수 있다면 화면에 고정되지 않는 항상 가장 마지막 요소로 접근하면 가장 쉽고

2. 이게 안된다면 js를 통해서 건드린 마지막 요소를 옵저버로 설정하고 마지막 요소의 뷰포트에 일정 비율 접근했을 때 callback 함수가 실행되고 지금 observe를 unobserve하는 것이다.

 

function handleIntersect(entries, observer) {
  entries.forEach((entry) => {
    if (entry.isIntersecting === true) {
      observer.unobserve(entry.target)  // target은 관찰 중인 대상을 가리킴
      fetchAlbums()                     // axios를 통한 json 데이터 가져오기
    }
  });
}

 

전체 흐름

// 윈도우의 이벤트로 인한 콜백 함수
function createObserver() {
  // 관찰할 태그 가져오기
  const target = document.querySelector('#watched')
  // 관찰 시작 -> 중요한 것은 한번 실행된다
  observer.observe(target)
}

// 옵저버가 일으킬 콜백함수
function handleIntersect(entries, observer) {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      observer.unobserve(entry.target);
      fetchAlbums()
    }
  });
}

// IntersectionObserver 객체의 인스턴스 생성
let observer = new IntersectionObserver(handleIntersect, options)

// 웹페이지 로드가 완료되면 실행하는 이벤트리스너
window.addEventListener(('load'), () => {
  console.log('change')
  // 옵저버 만들기
  createObserver()
}, false)