[React] 가로로 스크롤 진행률 표시하는 UI 만들기 (feat. 커스텀 훅)

2022. 6. 5. 11:31React

728x90

티스토리 블로그를 자주 쓰신다면 가로로 스크롤 진행률이 표시되는 UI를 많이 보셨을 것입니다.

많은 브라우저에서 세로 스크롤을 잘 안 보이도록 감춰놓는 경우가 많기 때문에 얼마나 읽어야지 콘텐츠가 끝이 나는지 짐작하기가 어렵습니다. 이때 가로 스크롤 진행률 UI를 사용한다면 사용자들도 콘텐츠의 길이를 한 번에 확인할 수 있고, 좋은 색상만 선택한다면 외관상 한층 업그레이드된 느낌을 받을 수 있습니다. 

 

아래 이미지는 필자가 개발하고 있는 웹에 해당 UI가 적용된 모습입니다.

 

가로 스크롤바 적용

 

해당 UI는 요구사항은 아니었지만 비교적 긴 매거진 콘텐츠에서 사용자가 얼마나 읽었는지 짐작할 수 있는 UI는 꼭 필요하다고 생각했기 때문에 추가하게 되었습니다. 추후에는 해당 바에 주요 제목들을 링크해두고 바로 이동할 수 있도록 기능을 추가할 예정입니다.

 


컴포넌트 만들기

본격적으로 컴포넌트를 만들기 위해서 아래와 같이 jsx를 작성해줍시다. 참고로 필자는 모듈 scss를 사용했기 때문에 아래와 같이 작성을 했고 다른 css 방식을 사용하시는 분은 알아서 맞게 변경을 해주시면 됩니다.

 

components/HorizontalProgress.jsx

import React from "react";
import styles from "styles/components/HorizontalProgress.module.scss";

const HorizontalProgress = ({ scroll }) => {
  return (
    <div className={styles.container}>
      <div className={styles.progress} style={{ width: scroll }}/>
    </div>
  );
};

export default HorizontalProgress;

 

styles/components/HorizontalProgress.module.scss

.container {
  width: 100%;
  background: #ccc;
  position: fixed;
  width: 100%;

  .progress {
    height: 8px;
    background: blue;
    width: 0%;
  }
}
css는 입맛에 맞게 변경해주시면 됩니다. 필자는 위 css에서 추가로  container의 최대 넓이, z-index 등을 설정해줬습니다. 
동작원리는 간단합니다. scroll prop을 %로 받으면 해당 % 만큼 progress의 길이가 적용되도록 했습니다. 당연히 %로 받을것이기 때문에 데스크탑에서 쓰던 모바일에서 쓰던 상관없이 잘 작동을 할것입니다.
이 %값을 구하기 위해선 커스텀 훅을 사용하겠습니다.

 

hooks/useDetectScroll.js

 

import { useState, useEffect, useCallback } from "react";

const useDetectScroll = () => {
  const [scroll, setScroll] = useState(0);

  const handleProgressBar = useCallback(() => {
    const totalScroll = document.documentElement.scrollTop;
    const windowHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
    const scroll = `${(totalScroll / windowHeight) * 100}%`;
    setScroll(scroll);
  }, []);

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

export default useDetectScroll;

 

해당 훅을 살펴보면, 스크롤 이벤트가 일어날 때마다 handleProgressBar라는 함수가 실행되도록 이벤트 리스너를 달아주고 있습니다. 

스크롤될 때 마다 실행되는 이 handleProgressBar 함수 내부에서는 scrollTop 메서드를 통해 수직 스크롤 위치를 px로 받고 화면 윈도 높이 (scrollHeight - clientHeight)까지 px로 받은 뒤 두 개의 값을 이용해 % 값을 구하고 해당 값을 상태 값으로 지정한 뒤 내보내 주고 있습니다.

 

요소 사이즈와 스크롤에 대해 좀 더 자세한 설명이 필요하신 분들은 해당 자료를 참고해주시길 바랍니다.

https://ko.javascript.info/size-and-scroll

사용하실 때에는 사용하고자 하는 곳에서 해당 훅을 호출한 뒤 반환되는 scroll값만 전에 만든 HorizontalProgress 컴포넌트에 넘겨주기만 하면 됩니다.

 

const Magazine = () => {
const { scroll } = useDetectScroll();

return (
 <HorizontalProgress scroll={scroll} />
 //...생략
 )
}

 

참고자료 : https://ko.javascript.info/size-and-scroll