무한 스크롤 - 무한 루프

Rock Kyun·2023년 12월 6일
2
post-thumbnail

오늘 했던 것

  • 협업의 페이지 중 사진 작가들의 포트폴리오를 나열하는 페이지 제작
  • 무한스크롤 도전
  • 무한 루프에 빠져 API 할당량 30초 내에 소진

오늘의 문제

  1. cleanUp function의 개념을 알고 있기에
    호기롭게 무한 스크롤을 시도했다가
    무한 루프에 빠져서 1시간 할당량을 무려 30초 내에 소진했다.

    사실 30초는 당황해서 로그에 찍힌
    74,000개를 넘어가는 오류를 본 때고
    아마 5초 내로 소진한 것으로 예상한다.)

원인

  • useEffectaddEventListener의 callback fn
    cleanup fn의 removeEventListener callback fn의 주소값이 달랐던 것

수정하기 전 작성한 코드는 이러하다

useEffect(() => {
    window.addEventListener('scroll', () => {
      
      // 현재 scroll양과 현재 브라우저 창의 높이가
      // body 전체의 height와 같거나 더 커진다면
      if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
        
        // 이미지 API의 pagination 기능을 위한 useRef며 초기값은 1
        // 첫 번째 호출은 1페이지, 다음은 2페이지.. 3페이지...
        ref.current++
        
        // 이미지를 더 불러주는 함수 호출
        loadMoreImages(); 
      } else {
        return;
      }
    });

    return () => {
      // 문제의 cleanup fn
      window.removeEventListener('scroll', () => {
        if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
          loadMoreImages();
        }
      });
    };
  }, []);
  • 각각의 eventListener는 동일한 동작을 하는 코드를 가지고 있다.
    그래서 addEventListenercallback fn를 그대로 가져와서
    removeEventListener에 주면 되는 줄 알았는데

    두 함수의 주소 값이 같아야 정상적으로 작동하는 것이다..
    객체는 타이핑한 글자가 같다고 같은 취급을 해주지 않고
    어느 메모리의 주소값을 참조하느냐에 따라 값이 같거나 다름을 구분
    한다.

// 객체형 데이터는 코드가 같다고 같은 것이 아님
const p1 = {id:0, name:'lee'}; 
const p2 = {id:0, name:'lee'}; 

console.log(p1===p2); // false

// 원시형 타입은 같다고 나옴
let a = 0;
let b = 0;
console.log(a===b); // true

문제 해결

  • 1급 객체인 함수의 주소값을 동일하게 하기 위해
    callback fn의 코드를 useEffect 밖에서 만든 뒤
    window.addEventListener
    window.removeEventListener에 각각 callback fn으로 전달해준다.
// 스크롤 이벤트에 따라 작동하는 함수
const onScrollHandler = () => {
    if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
      ref.current++;
      loadMoreImages();
    } else {
      return;
    }
  };

  // 이제 같은 주소값을 가진 함수가 전달이 되어
  // 정상적으로 작동한다.
  useEffect(() => {
    window.addEventListener('scroll', onScrollHandler); 

    return () => {
      window.removeEventListener('scroll', onScrollHandler);
    };
  });

결과물

0개의 댓글