특정 컴포넌트가 overflow되었는지 확인하는 hook

박진현·2023년 11월 8일
0

이전 글 에서 떠오른 아이디어를 쓰다가 재사용해야할 경우가 생겨서 훅으로 만들었다.

import { RefObject, useEffect, useRef, useState } from 'react';

/**
 *  주어진 HTML 요소에서 오버플로우를 감지하는 커스텀 훅입니다.
 *  * @example
 *  const [elementRef, isOverflowed] = useIsOverflow('x', someDependency);
 *  elementRef로 참조된 요소에서 수평 방향의 오버플로우를 체크합니다.
 *
 *  🚨🚨 꼭! Overflow 요소에 ref를 걸어주세요 🚨🚨
 *
 * @template T - HTMLElement의 타입 (기본값은 HTMLElement).
 * @param {string} direction - 체크할 오버플로우 방향입니다. 가능한 값은 다음과 같습니다:
 *   - 'x': 수평 (x) 방향에서의 오버플로우를 체크합니다.
 *   - 'y': 수직 (y) 방향에서의 오버플로우를 체크합니다.
 *   - 'x|y': 수평과 수직 방향에서의 오버플로우를 체크합니다.
 *   - 'x&y': 수평과 수직 방향에서의 오버플로우를 체크합니다 (둘 다 오버플로우여야 함).
 * @param {any=} dependency - 변경 시 업데이트를 트리거할 의존성입니다.
 *  - 이 값이 변경되면, 해당 요소의 오버플로우 상태를 다시 계산합니다.
 *  - default 값은 undefined 이고, 이때는 마운트 되었을 때, 단 한번만 계산합니다.
 *  - 🚨주의🚨 Array , Function , Object 등 참조타입을 입력하면 메모리 주소가 변경될 때마다 매번 재계산합니다.
 * @returns {[RefObject<T>, boolean]} 해당 요소에 대한 ref 객체와 오버플로우 상태를 나타내는 boolean 값을 포함하는 튜플을 반환합니다.
 *
 */
function useIsOverflow<T extends HTMLElement = HTMLElement>(
  direction: 'x' | 'y' | 'x|y' | 'x&y' = 'y',
  dependency?: any
): [RefObject<T>, boolean] {
  const elementRef = useRef<T>(null);
  const [isOverflowed, setIsOverflowed] = useState(false);

  useEffect(() => {
    const element = elementRef.current;

    if (!element) return;

    switch (direction) {
      case 'x':
        // x축 방향이 오버플로우인지 확인
        return setIsOverflowed(element.scrollWidth > element.clientWidth);
      case 'y':
        // y축 방향이 오버플로우인지 확인
        return setIsOverflowed(element.scrollHeight > element.clientHeight);
      case 'x|y':
        // 모든 방향이 오버플로우인지 확인
        return setIsOverflowed(
          element.scrollWidth > element.clientWidth ||
            element.scrollHeight > element.clientHeight
        );
      case 'x&y':
        return setIsOverflowed(
          element.scrollWidth > element.clientWidth &&
            element.scrollHeight > element.clientHeight
        );
      // 모든 방향이 오버플로우인지 확인
      default:
        return setIsOverflowed(false); // 지정된 방향이 아닌 경우, 오버플로우 없음
    }
  }, [elementRef, direction, dependency]);

  return [elementRef, isOverflowed];
}

export default useIsOverflow;



profile
👨🏻‍💻 호기심이 많고 에러를 좋아하는 프론트엔드 개발자 박진현 입니다.

0개의 댓글