본문 바로가기

[custom hook] 페이지 최상단으로 이동하는 버튼

[custom hook] 페이지 최상단으로 이동하는 버튼

구현한 기능

 

위로 이동 버튼

세부 기능 :

  1. 일정 스크롤 이상일 때 나타남
  2. 클릭하면 스크롤 최상단으로 부드럽게 이동 

 

구현한 방법

 

커스텀훅

 

의사 코드

  1. window에 scroll 이벤트 등록 (useEffect) 
    • 이벤트 : 스크롤 했을 때 스크롤 높이가 1000px이상 이면 버튼이 보이도록 상태 변경
                   (isShowBtn = true)
  2. click했을 때 스크롤 높이가 0px(화면 최상단)으로 부드럽게 이동하는 함수 생성
  3. 2번의 버튼이 보이는지 여부 상태와 3번의 함수를 return
  4. 버튼 컴포넌트에서 isShowBtn 상태에 따라 opacity 값이 달라지도록 클래스네임 동적으로 변경
  5. 버튼 컴포넌트의 onClick 속성에 3번 함수 매칭

 

useScrollMoveToTop.ts
import { useEffect, useState } from 'react';

export const useScrollMoveToTop = () => {
  const [isShowBtn, setIsShowBtn] = useState(false);

  const handleScroll = () => {
    if (window.scrollY > 1000) {
      setIsShowBtn(true);
    } else {
      setIsShowBtn(false);
    }
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, []);

 // 어차피 hydration 이후에 버튼 onClick 이벤트가 실행되는 것이기 때문에 window !== undefined 조건을 걸 필요가 없다. 
  const handleMoveToTop = () => {
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };

  return { isShowBtn, handleMoveToTop };
};

 

 

버튼 컴포넌트에 hook 적용

 

MoveToTopBtn.tsx

react-icons 라이브러리를 활용하여 위로 향하는 화살표 아이콘이 담긴 버튼을 만들었다. 

  • aria-label 등 상수 값도 따로 모듈화시켜주는 것이 좋다.
'use client';

import { FaRegArrowAltCircleUp } from 'react-icons/fa';
import { useScrollMoveToTop } from '@/hooks/useScrollMoveToTop';
import styles from './MoveToTopBtn.module.scss';

// 동적 언어 라우팅 적용된 상태 (한국어 또는 영어)
const MoveToTopBtn = ({ lng }: { lng: string }) => {

  // 커스텀훅 호출
  const { isShowButton, handleMoveToTop } = useScrollMoveToTop();

  return (
    <button
      type="button"
      className={`${styles.container} ${isShowButton ? styles.visibility : ''}`}
      onClick={handleMoveToTop}
      aria-label={lng === 'ko' ? '위로 이동하기' : 'back to top'}
    >
      <FaRegArrowAltCircleUp size={33} />
    </button>
  );
};

export default MoveToTopButton;

 

MoveToTopBtn.module.scss
.container {
  position: fixed;
  z-index: 500;
  right: 3%;
  bottom: 3%;
  transition: all .3s;
  opacity: 0;
  color: var(--color-primary); 

  &:hover ~ svg {
    font-size: 45;
  }

  &.visibility {
    opacity: 1;
  }

  &:active {
    bottom: 2.5%;
  }
}

 

728x90
⬆︎