문제의 발생

2년 전 거의 코딩을 시작하기 처음 만들었던 프로젝트를 다시 열어본다. 코드를 오래 유심히 보지 않아도 사실 문제가 뭔지 알 수 있었다. 마치 2년전 쓴 일기를 보는 것 같이 반갑지만, 코드들을 보며 부끄러운 마음이 앞 선다.

image.png

  //slides.js
  const { scrollHandler } = useContext(NavContext)
  
  const onScroll = (e) => {
    let screenY = e.currentTarget.scrollTop;
    if (screenY < 1) {
      scrollHandler(1);
    } else {
      scrollHandler(screenY);
      console.log(screenY);
    }
  };
 

우선 문제가 되는 코드이다. 스크롤을 진행하면 screenY 값이 useContext에 기록이 되어 아래 코드의 scrollReached의 값을 true로 변경하여 아래 컴포넌트를 애니메이션과 함께 보여준다.

  //SecondSlide.js
  {scrollReached && (
  <section className={classes.main_container}>
    <figure className={classes.slide_figure}>
      <img className={classes.img_wrapper} src={caption_img} alt="등산" />
      <figcaption className={classes.caption_wrapper}>
        <h2>{text[0]}</h2>
        <h1>{title}</h1>
        <p>{text[1]}</p>
      </figcaption>
    </figure>
  </section>
)}

하지만, 그 당시 신경 쓰지 못 했기 때문에 맨 위에 첨부한 사진 처럼 스크롤 이벤트가 발생할 때 마다 주루룩 찍히고 있다


문제에 접근 하기

이렇게 계속해서 발생하는 함수를 처리하는 방법은 정해진 시간으로 묶어서 한번 실행 (스로틀링) 처리하거나 앞이나 뒤의 함수만 처리하거나 (디바운싱) 두 가지 방법이 있다. 검색창을 구현할 때는 앞이나 뒤 이벤트만 처리해야 하는 경우이므로 디바운싱이 적합하고, 스크롤은 연속적인 동작을 감지해야 하므로 스로틀링이 적합하니 스로틀링을 적용해보자.


문제의 해결

  // scorll 값을 저장하는 context
  const { scrollHandler } = useContext(NavContext)
  // 스로틀링 ref 값
  const throttleTimeout = useRef(null)
  
  // 스로틀링 적용된 스크롤 핸들러
  const onScroll = (e) => {
    if (!throttleTimeout.current) {
      throttleTimeout.current = setTimeout(() => {
        const scrollTop = e.target.scrollTop;
        scrollHandler(scrollTop || 1);
        // 타이머 초기화
        throttleTimeout.current = null;
      }, 500);
    }
  };

500ms에 한 번만 발생하도록 한다. throttleTimeout의 값이 없을 경우에 타임아웃을 통해 scrollHandler 스크롤 값을 전역에 저장한다. 500ms에 throttleTimeout의 값이 null으로 reset이 되고 그동안 발생된 이벤트는 무시된다. 이러한 단순한 로직만 적용을 해주면 이벤트가 아래 사진처럼 스크롤 값이 훨씬 더 적게 찍한다.

image.png


글을 마치며

지금도 부족하지만, 그때는 성능 최적화에 훨씬 더 무심했던 것 같다. 간단히 코드 몇 줄만 추가하면 해결될 문제였는데 말이다. ‘배우는 입장이니까 라이브러리를 쓰지 않고 최대한 직접 구현해보자’라고 생각하며 만든 프로젝트였지만, 정작 가장 중요한 성능이라는 요소를 놓치고 있었다. 아마 그 부분뿐만 아니라 컴포넌트 분리 등 여러 측면에서 개선할 점이 많을 것이다. 하지만 개선하는 것보다 처음부터 다시 짜는 것이 훨씬 나을 것 같다는 생각이 든다.

나의 치부를 드러내는 것 같아서 오랬동안 예전에 짠 코드를 보지 않았다. 앞으로는 그러지 않는 편이 더 좋겠다.