무한스크롤을 해야한다.
간단히 가장 끝에 있는 요소까지 스크롤하면 새로운 목록을 불러와 이어붙이는것이다.
내가 찾아본 바로는 크게 두가지 방법이 있다. 하나는 스크롤 이벤트를 이용하는것이고 다른 하나는 intersection observer라는 기능을 이용하는것이다. 이 중 내가 사용한 기능은 intersection observer이다. 그 이유는 다음과 같다.
이러한 이유로 intersection observer를 사용해보기로 했다. 사용해보니 정밀한 좌표값보다 마지막 요소가 화면에 표시되었는지 아닌지가 필요한 무한스크롤 같은 기능은 intersection observer가 더 좋아보였다. react와 잘 어울리기도 하다.
MDN의 Intersection Observer API 문서
intersection observer api는 타겟 요소와 상위 요소 또는 최상위 document 사이의 intersection 변화를 비동기적으로 관찰하는 방법입니다
root값으로 넘겨줄 수 있는 상위 요소와, observer로 감시중인 타겟 요소 사이의 intersection을 비동기적으로 관찰하여 감시중인 타겟이 root요소의 viewport에 들어가거나 나가는것에 따라 콜백을 실행한다.
예제 코드로 보자면,
let options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 1.0
}
let observer = new IntersectionObserver(callback, options);
observer.observe(target);
root: 기준이 되는 상위 요소
rootMargin: 기준 요소로부터 보여지는 영역까지의 마진
threshold: 대상 요소가 root요소 내에 얼마나 보여질 때 콜백이 실행될 것인지를 결정. 0~1 사이로 1이면 100% 보여질 때 실행. 배열로 [0, 0.3, 1] 이런식으로 여러 구간마다 콜백이 실행되게 할 수도 있다.
콜백은 observe한 대상 entry배열과 observer를 파라미터로 가지는 함수로
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
});
};
이렇게 구성할 수 있다. observer.observe()로 관찰대상을 추가할수도 있고 unobserve()로 관찰을 중지하거나 disconnect()로 모든 요소의 관찰을 중지할 수도 있다.
intersection observer를 사용하며 조금 문제가 있었는데, 일단 실행은 잘 됐다. 등록한 콜백에 따라 마지막 요소가 화면에 보이면 다음 요소를 불러오는 함수를 실행했고, 다음 요소를 목록에 추가해 늘어난 뒤 다시 마지막 요소의 ref에 intersection에 사용될 ref를 넘겨주어 intersection을 감지했다.
그런데 이 콜백이 의도한대로 맨 마지막 요소의 화면 표시에만 실행되지 않고 맨 처음 마운트할때도 동작하고 스크롤을 넘길때도 여러번 동작하는 등 의도치않은 실행이 너무 많았다. 이걸 컨트롤하기위해 entry.intersectionRatio를 확인해 체크하는 로직을 추가하기도 했지만 완전히 해결할 순 없었다.
결국 갖은 노력에도 문제의 원인을 찾지 못하고 react-use에 있던 useIntersection을 사용해 해결했다(내가 작성한것과 크게 다른건 모르겠는데 일단 됐다).
지금 보니 MDN문서의
Intersection observer 의 컨셉과 사용
Intersection Observer API는 다음과 같은 상황에 호출되는 콜백을 생성하는 기능을 제공합니다:
(1) 대상(target) 으로 칭하는 요소가 기기 뷰포트나 특정 요소(이 API에서 이를 root 요소 혹은 root로 칭함)와 교차함.
(2) observer가 최초로 타겟을 관측하도록 요청받을 때마다.
이 부분이 문제가 아니었을까? observer가 등록되며 콜백이 실행된것이고 새로운 요소가 추가된 뒤에도 ref를 옮기며 새로 observer가 관측을 하게되어 콜백이 중복해서 실행된.. 그런느낌이든다. 다음에 다시 테스트해봐야겠다.