KooKs

useThrottle

빠르게 변경되는 값을 일정 시간 간격으로만 업데이트하는 커스텀 훅
ReactTypescript

예시

실제 값: -
스로틀된 값: -
500ms 동안 값이 변경되지 않으면 업데이트됩니다.

API

useThrottle<T>()
  • Parameters
    • callback ((...args: Args) => Return)스로틀링할 콜백 함수
    • limit (number)실행을 허용할 시간 간격(ms)
  • Returns
    • (...args: Args) => Return | undefined (function)스로틀링된 함수. 이 함수는 원본 함수와 동일한 매개변수를 받지만, limit 시간 간격으로만 실행됩니다.

개발 및 사용환경

ReactTypescript

사용법

1// 기본 사용
2const [value, setValue] = useState("");
3const [throttledValue, setThrottledValue] = useState(value);
4
5const handleChange = useThrottle((newValue: string) => {
6  setThrottledValue(newValue);
7}, 500);
8
9useEffect(() => {
10  handleChange(value);
11}, [value, handleChange]);
12
13// 스크롤 이벤트 스로틀링
14const handleScroll = useThrottle(() => {
15  console.log(window.scrollY);
16}, 100);
17
18useEffect(() => {
19  window.addEventListener("scroll", handleScroll);
20  return () => window.removeEventListener("scroll", handleScroll);
21}, [handleScroll]);

Hook

1import { useCallback, useRef } from "react";
2
3/**
4 * 콜백 함수를 일정 시간 간격으로만 실행하는 Hook
5 * 
6 * 이 훅은 함수가 너무 자주 호출되는 것을 방지하여 성능을 최적화합니다.
7 * 예를 들어, 스크롤 이벤트나 리사이즈 이벤트와 같이 빠르게 연속으로 발생하는 이벤트를 처리할 때 유용합니다.
8 *
9 * @param callback - 스로틀링할 콜백 함수
10 * @param limit - 실행을 허용할 시간 간격(ms)
11 *   - 0 이하: 경고 메시지 출력 후 즉시 실행
12 *   - 양수: 지정된 간격으로만 실행
13 *
14 * @returns 스로틀링된 함수. 이 함수는 원본 함수와 동일한 매개변수를 받지만, 
15 *         limit 시간 간격으로만 실행됩니다.
16 */
17export function useThrottle<Args extends unknown[], Return>(
18  callback: (...args: Args) => Return,
19  limit: number
20): (...args: Args) => Return | undefined {
21  const lastRan = useRef(Date.now());
22  const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
23
24  return useCallback(
25    (...args: Args) => {
26      if (limit <= 0) {
27        console.warn("useThrottle: limit must be a positive number");
28        return callback(...args);
29      }
30
31      const now = Date.now();
32      const timeSinceLastRun = now - lastRan.current;
33
34      if (timeSinceLastRun >= limit) {
35        // 마지막 실행 후 limit 시간이 지났으면 즉시 실행
36        lastRan.current = now;
37        return callback(...args);
38      } else {
39        // 아직 limit 시간이 지나지 않았으면 나머지 시간만큼 대기 후 실행
40        if (timeoutRef.current) {
41          clearTimeout(timeoutRef.current);
42        }
43
44        timeoutRef.current = setTimeout(() => {
45          lastRan.current = Date.now();
46          callback(...args);
47        }, limit - timeSinceLastRun);
48      }
49    },
50    [callback, limit]
51  );
52}