이전 글 에서 떠오른 아이디어를 쓰다가 재사용해야할 경우가 생겨서 훅으로 만들었다.
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;