이렇게 하게 됨으로써 생기는 문제가 있다. 바로 스크롤이 될 때 마다 handleScroll 이 동작하는 것이다.handleScroll 메서드는 결국 자바스크립트의 메인엔진에서 실행이 되어야하므로 많은 부하가 걸리게 된다.
이런 문제를 해결해 줄 수 있는게 바로 intersection-observer API 이다.
그렇다면 어떻게 위의 문제를 해결해줄 수 있을까?
간단하다. intersection observer API 는 Web API 이기 때문이다!! 즉, 스크롤이 일어날 때 마다 자바스크립트의 코드를 곧잘 돌려야하는 이전과는 달리 해당 API 를 사용하면 자바스크립트 엔진과는 상관없이 브라우저단에서만 무한스크롤 로직을 검사하고, 조건을 통과하는 경우에는 자바스크립트의 코드로 데이터를 불러오면 되는것!
Intersection Observer에 대해 알아보자.
intersection observer의 흐름을 알아보자
intersection observer 는 무한스크롤에만 사용되는건 아니다...
이 API는 크게 관찰자(observer) 와 관찰 대상(entry), 옵션(조건) 그리고 콜백함수(로직) 이 존재한다.
해당 링크 에서 스크롤을 내려 Targeting an element to be observed 를 보자. 여기를 보면 callback 을 어떻게 정의해야하는지를 알려준다.
즉 조건을 만족하게 될 경우 Intersection-observer API 는 콜백함수 에게 entries 를 주게 된다. 그리고 이 entries 는 관찰 대상의 리스트다. 따라서 사용자는 이 관찰 대상의 리스트 에서 지금 조건을 만족한 관찰 대상 을 찾고 우리가 원하는 로직을 실행해주면 되늑 것이다!!!!
준비는 끝났다. 리액트에서 실제 코딩을 해보자
코딩을 하기 전에 생각할것
Intersection Observer 의 조건으로 무엇을 넣어줄 것인가.
스크롤바가 바닥에 닿으면 새로운 데이터를 불러오게 만들자.
관찰 대상 은 무엇인가?
관찰 대상은 리스트의 맨 아래에 비어있는 html 태그로 선언한다.
어떤 로직(콜백함수) 를 넣어줄 것인가?
새로운 데이터를 불러오는 로직을 넣는다.
만드는 순서
관찰 대상을 만들자
리스트의 맨 아래에 관찰 대상 을 만든다. 여기서 중요한건 ref={setObservationTarget} 다.
관찰자 를 만들자
관찰 대상이 하나이므로 콜백함수 의 인자로 들어오는 entries 에서 구조화할당? 을 이용해 entry 하나만을 가져온다. 그리고 이 entry 의 속성인 isIntersecting 를 이용해 조건을 검사하고, 콜백함수 를 실행한다.
자, 이렇게 관찰자, 관찰 대상, 조건, 콜백함수 를 다 만들었으니 끝난걸까? 아니다. 지금 이대로 실행하면 절대 원하는 결과를 얻지 못한다. 왜? 관찰 대상 은 새로운 데이터를 가져올 때 마다 변해야하기 때문!!!
관찰 대상을 수시로 변경해주자
리액트에서 무언가 변하고 이에대한 처리를 해줄 때 사용하는 훅이 있다. 바로 useEffect
스크롤을 내린다.
관찰 대상을 만나고, 조건을 만족시킨다.
새로운 데이터를 가져온다.
이 때 state 의 loading 이 true 이므로 관찰 대상 이 사라진다.
새로운 데이터를 리스트에 추가한다.
loading 이 다시 false 가 되므로 관찰 대상 이 다시 렌더링된다.
관찰 대상 이 다시 렌더링 됐지만, 3번과 4번의 과정에서 지워지고 새롭게 만들어졌다.
따라서 지워진 관찰 대상 은 관찰 대상 리스트 에서 제거해줘야하고
새롭게 관찰 대상을 지정해줘야한다.
이런 로직을 담당할 수 있게 해주는 코드는 아래와 같다.
관련 로직을 커스텀훅으로 만들자
왜 커스텀 훅으로 만들어야하는가? 해당 로직을 따로 분리하면 분명 다른 프로젝트에서 사용할 수 있을거로 보이기 때문!
코드
의문점
useEffect 에서 clean-up 을 꼭 해줘야하는가?
해줘야한다!! 실행상에 문제는 없다. 다만 이전의 타겟이 남아있기 때문에 callback 이 쓸데없이 더 불러와지는 문제가 있다(물론 callback이 실행되도 isIntersecting에서 걸리기 때문에 대부분의 경우 걱정할 필요가 없지만...)
clean-up 은 useEffect 에서 가장 먼저 실행된다. 따라서 현재의 로직을 실행하기 전에, closure로 이전의 데이터가 존재하면 clean-up 해주는 것.
사용법
무한스크롤 이 필요한 컴포넌트에서 해당 훅으로 setObservationTarget 을 선언한다. 실행할 로직을 인자로 넘겨준다!!