sumini dev

posts

Scroll Direction Hook 만들기

profile-image

Choi su min

헤더가 컨텐츠를 가리지 않게 하기 위해, Scroll Direction에 따라 유동적으로 나타나도록 만들 필요가 있었다. EventListener와 state를 이용해 쉽게 유동적인 헤더를 구현할 수 있다.

구현

const useScrollDirection = (initialDirection?: 'up' | 'down') => {
  const [direction, setDirection] = useState(initialDirection || 'up');
  const [lastPosition, setLastPosition] = useState(0);

  useEffect(() => {
    const handleScroll = () => {
      if (window.scrollY < 100) return; // 최상단에서는 연산하지 않는다.
      if (Math.abs(lastPosition - window.scrollY) > 15) {
        // 15px 이상 스크롤했을 때만 연산한다.
        setDirection(lastPosition > window.scrollY ? 'up' : 'down');
        setLastPosition(window.scrollY);
      }
    };
    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll);
      // unmount시 제거해준다.
    };
  });
  return direction;
};

export default useScrollDirection;
useScrollDirection.ts

저장된 스크롤 위치와 현재 위치를 비교해 direction을 구합니다.

15px이상 차이날때만 변경되도록해 안정성을 높입니다.

적용

import useScrollDirection from 'src/hooks/useScrollDirection';

export default function MainHeader(props: IProps) {
  const scrollDirection = useScrollDirection('down');

  return (
    <Header
      style={{ position: scrollDirection === 'up' ? 'fixed' : 'relative' }}
    >
      ...
    </Header>
  );
}
header.tsx

위와 같이 어디에서나 사용할 수 있다!

+) Class형 component에서의 구현

state

this.state = {
  scrollDirection: 'down',
  lastScrollPos: 0,
};

listener 추가/제거

componentDidMount = () => {
  window.addEventListener('scroll', this.onScroll);
};

componentWillUnmount = () => {
  window.removeEventListener('scroll', this.onScroll);
};

component가 mount될때 listener를 추가하고, unmount될때 제거해준다.

listener 작성

onScroll = () => {
  const { lastScrollPos } = this.state;

  if (lastScrollPos > window.scrollY + 15) {
    this.setState({
      scrollDirection: 'up',
      lastScrollPos: window.scrollY,
    });
  } else if (lastScrollPos < window.scrollY - 15) {
    this.setState({
      scrollDirection: 'down',
      lastScrollPos: window.scrollY,
    });
  }
};

REACT8개 더보기

HOOKS1개 더보기

모든 글 보기

이전 글

CI, CD 제대로 정리하기

다음 글

Query Parameter Hook 만들기

profile-image

Choi su min

Sogang Univ.

AWESOME.DEV Lead

Anyang, Gyeong-gi, Republic of Korea

github-iconmail-iconrss-icon