사이드 프로젝트를 진행하며 유저가 스크롤을 내릴 때도 상단에 유지되는 header를 간단하게 만들어 보았다..이름하여 sticky header..
Sticky Header는 위 이미지처럼 대부분의 웹 서비스에서 적용되고 있는 방식으로 유저가 스크롤을 할 때 header가 상단에 유지시켜 스크롤 상태와 무관하게 유저가 navigator 나 검색창을 사용할 수 있도록 하는 기능이다. 개인적으로 Excel에서 셀 고정이 필수인 것처럼.. 웹 사이트에도 Sticky header도 필수라고 생각한다. 없으면 너무 불편하다!!
사실 처음에는 window의 scroll가 발생할 때마다 현재 Y축의 위치를 찾아 이를 state로 업데이트 해주면 되겠지 싶었다. 하지만 scroll 이벤트는 말 그대로 유저가 scroll을 조금만 내려 Y의 위치가 아주 조금만 변경되어도 이벤트가 핸들러가 실행되기 때문에.. 또 유저의 scroll 이벤트가 빠른 속도로 실행될 수 있기 때문에.. scroll을 할 때마다 state를 하겠다는 생각은!! 멈춰~!!!야 한다.
아래는 scroll 이벤트에 따른 state값을 console에 찍어본 결과인데, 보이는 것과 같이 scroll 이벤트에 따라 state를 변경하면 한 번의 스크롤로 인해 state가 수 십번 바뀌게 되니 해당 컴포넌트가 수 십번 불필요하게 리렌더링 될 수 밖에 없다!!
scroll 이벤트가 빠른 속도로 실행될 수 있기 때문에, 이벤트 핸들러는 DOM 수정과 같이 느린 작업을 실행하지 말아야 합니다. 대신, requestAnimationFrame(), setTimeout(), 혹은, CustomEvent을 사용하여 이벤트를 제한하는 것을 권장합니다.
MDN-scroll
MDN에서 말하는 것처럼 빠른 속도로 실행되는 scroll 이벤트를 제어할 방식이 필요하다. DOM event를 제어하는 대표적인 방법으로는 debounce와 throttle이 있는데, 간단하게 말하면 1초짜리 debounce와 throttle을 걸었다고 했을 때 debounce는 유저의 마지막 scroll event가 일어난 시점에서 1초 후에 event를 1번 실행시키고, throttle은 1초 동안 딱 1번의 event만 실행시킨다.
이번에는 유저가 스크롤을 한 즉시!! 표준 header에서 Sticky Header로 변환시키는 작업이 필요하기 때문에 이벤트 발생 시점 부터 정해진 시간이 지난 후 이벤트를 발생시키는 debounce 보다는 여러 번 발생하는 이벤트를 일정 시간 동안 한번만 실행시키는 throttle이 적합하다는 생각이 들어 throttle 통해 scroll event를 제어했다.(참고로 throttle에 사용할 setTimeout() Web API는 호출 시점을 millisecond 단위로 설정할 수 있기 빠른 스크롤 이벤트도 충분히 잡을 수 있다!)
if(!timer)
일때 아래 코드를 실행시키는 방법으로 해도 괜찮다.)*참고로 setTimeout의 리턴값을 받는 timer 변수의 type을 number로 주고 싶다면 아래처럼 setTimeout 앞에 window를 명시에 주면 된다.
window.setTimeout(() => {...}, delay);
const [scrollFlag, setScrollFlag] = useState(false);
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
const handleScroll = throttle(updateScroll, 100);
const updateScroll = () => {
const { scrollY } = window;
const isScrolled = scrollY !== 0;
setScrollFlag(isScrolled);
};
참고
MDN scrollY
잘 봤어요!! 궁금한 점이 있습니다 !
스크롤 이벤트에 따라서 다른 컴포넌트가 렌더되는 건가요?? 쓰로틀로 어떻게 컴포넌트에 작용하는지 궁금해요 !
그리고 만약 저라면,,그냥 특정 scrollY값에 도달하면 header를 없애거나 할 것 같은데..쓰로틀로 구현하신 이유가 궁금해요 !
https://developer.mozilla.org/ko/docs/Web/CSS/position
position에 sticky라는 속성을 사용하면 css만으로도 구현이 가능합니다!
잇님 글 잘봤습니다~ 좋아요 꾸욱!~
스티키 헤더? 이름 완전 귀여운데용?