무한 스크롤은 페이지의 최하단에 도달했을 때, 새로운 콘텐츠를 받아와서 로딩하는 방식으로 동작한다. 이번에는 무한 스크롤을 통해 이미지 그리드를 만든 뒤, 화면의 최하단에 도달하면 추가 이미지를 로드해오는 기능을 구현할 것이다.
이렇게!
동영상 만들면서 스크롤을 잘라버렸지만 ... 실제로는 스크롤이 하단에 닿았을 때, 새로운 이미지가 로드된다.
Intersection Observer는 이 전에 FadeIn animation을 구현할 때 잠시 다뤄본 적이 있다. 비슷한 맥락으로 target 을 관찰해서 특정 위치에 도달했을 때 이벤트(ex. 이미지 로드)를 실행시키는 로직으로 무한 스크롤을 구현하면 될 것같다.
요거 ! custom hooks 를 이용하여 scroll event 만들기
new IntersectionObserver()
를 통해 observer 인스턴스를 생성한다. 생성한 observer 로 관찰할 대상을 지정할 수 있다.
new IntersectionObserver()
생성자는 두 개의 매개변수(callback 함수, options)
를 갖는다.
// observer 인스턴스 생성
let options = {
root: null,
rootMargin: '0px',
threshold: 0.5
}
const observer = new IntersectionObserver(callback, options);
target(관찰 대상)이 등록되거나, 가시성에 변화가 생기면 실행된다.
콜백 함수는 두개의 매개변수(entries, observer)
를 가지고 있다.
나는 이미지 무한 스크롤을 구현할 것이기 때문에 fetchNextImage
라는 함수를 만들어서, 다음 리스트(이미지)를 불러오도록 했다.
fetchNextImage
: 교차 상태가 됐을 때 실행할 함수 const callback = (entries, observer) => {
entries.forEach((entry) => {
entry.isIntersecting && fetchNextImage();
});
}
Intersection Observer 의 콜백 함수 호출 조건
(1) target(관찰 대상)이 뷰포트나 지정해준 root 요소와 교차할 때
(2) 관찰자(observer)가 최초로 타겟을 관측하였을 때
관찰 대상이 루트 요소와 교차 상태인지 아닌지 반환한다.
const callback = (entries) => {
entries.forEach((entry) => {
console.log(entry.isIntersecting);
// true 혹은 false 출력
});
};
target(관찰 대상)의 관찰을 시작할 때 사용한다.
나는 이미지 그리드를 target 으로 하기 때문에 그리드의 끝에 target을 지정해두었고,observe()의 인수로 넣어서 관찰 대상으로 지정했다.
const target = useRef(null);
// 코드 생략
<>
<StyledWrapper>
<div className="photo-list-wrap">{images}</div>
<div ref={target} className="infinity-point" />
</StyledWrapper>
</>
// 코드 생략
observer.observe(target);
target(관찰 대상)의 관찰을 중지할 때 사용한다.
observer.unobserve(target);
observer 가 관찰하는 모든 target의 관찰을 중지할 때 사용한다.
observer.disconnect();
options는 observer 인스턴스를 생성할 때 필요한 인수이다. 아래 세가지 값을 옵션으로 지정할 수 있다.
let options = {
root: null,
rootMargin: '0px',
threshold: 0.5
}
const observer = new IntersectionObserver(callback, options);
관찰 대상의 가시성 기준이 되는 화면이다. null
이거나 지정되지 않으면 브라우저의 뷰포트로 설정된다.
target(관찰 대상)의 가시성이 얼마나 필요한지를 나타내는 값이다.
ex) threshold = 0.5 -> 타겟의 가시성이 50%일 때 옵저버가 실행된다.
root가 가진 바깥 여백(margin)이다.
장점
- 사용자는 별도의 추가 동작(ex. 버튼 클릭 등)이 필요없이 편리하게 사용할 수 있다.
단점
- 스크롤을 내리면서 많은 컨텐츠를 로드했을 때, 원하는 콘텐츠를 다시 찾거나 해당 위치로 돌아가기 어렵다.
- 한 페이지 내에 상대적으로 많은 컨텐츠가 로드될 가능성이 있기 때문에, 성능이 저하될 수 있다.