useDebounce, useThrottle - boostcamp-2020/Project15-C-Client-Based-Formula-Editor GitHub Wiki

useDebounce์™€ useThrottle์€ debounce์™€ throttle์ด ์ ์šฉ๋œ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” hook์ด๋‹ค.

timer๋ฅผ useRef๋กœ ํ•˜์—ฌ ๋ฆฌ๋ Œ๋”๋ง ๋ผ๋„ timer๊ฐ€ ์ดˆ๊ธฐํ™” ๋˜๋Š” ํ˜„์ƒ์„ ๋ง‰๋Š”๋‹ค.

callback ํ•จ์ˆ˜์˜ ํƒ€์ž… ์ถ”๋ก ์„ ์ž˜ํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ <T extends any[]> ๋ฅผ generic์œผ๋กœ ๋ฐ›๋Š”๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ์ด์œ ๋Š” ...params ํ˜•ํƒœ๋กœ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ์ด๋‹ค. callback ํ•จ์ˆ˜์˜ ์ธ์ž๊ฐ€ ๋ช‡๊ฐœ๊ฐ€ ๋“ค์–ด์˜ฌ์ง€ ๋ชจ๋ฅด๋‹ˆ ์œ„ ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

ํ•ด๋‹น hook์€ ๋‘˜ ๋‹ค ๋˜‘๊ฐ™์ด callback๊ณผ time์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š”๋‹ค.

debounce๋Š” time ์•ˆ์— ํ•จ์ˆ˜๊ฐ€ ํ•œ๋ฒˆ๋” ์‹คํ–‰๋˜๋ฉด ์•ž์˜ ์ž‘์—…์„ ์ทจ์†Œํ•˜๊ณ  time์ด ์ง€๋‚  ๋•Œ๊นŒ์ง€ ๋‹ค์‹œ ํ˜ธ์ถœ ๋˜์ง€ ์•Š์œผ๋ฉด callback์„ ์‹คํ–‰ํ•˜๋Š” ํ˜•์‹์œผ๋กœ ๋˜์–ด์žˆ๋‹ค.

throttle์€ time ๋’ค์— callback์ด ์‹คํ–‰๋˜๊ณ  time์ด ์ง€๋‚˜๊ธฐ์ „ ๋‹ค์‹œ ํ˜ธ์ถœ๋  ๊ฒฝ์šฐ ์•„์ง time์ด ์ง€๋‚˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— callback์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒ์‹œํ‚ค๋Š” ํ˜•ํƒœ๋กœ ๋˜์–ด์žˆ๋‹ค.

์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ์ด์ œ ์–ด๋–ค ํ•จ์ˆ˜๋“  debounce ์™€ throttle์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

useDebounce

import { useRef } from 'react';

function useDebounce<T extends any[]>(callback: (...params: T) => void, time: number) {
  const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
  return (...params: T) => {
    if (timer.current) clearTimeout(timer.current);

    timer.current = setTimeout(() => {
      callback(...params);
      timer.current = null;
    }, time);
  };
}

export default useDebounce;

useThrottle

import { useRef } from 'react';

function useThrottle<T extends any[]>(callback: (...params: T) => void, time: number) {
  const timer = useRef<ReturnType<typeof setTimeout> | null>(null);

  return (...params: T) => {
    if (!timer.current) {
      timer.current = setTimeout(() => {
        callback(...params);
        timer.current = null;
      }, time);
    }
  };
}

export default useThrottle;

์‹ค์ œ ์‚ฌ์šฉ ์˜ˆ

const onScroll = (e: React.UIEvent<HTMLDivElement>) => {
    const target = e.target as HTMLDivElement;
    const scrollHeight = target.scrollHeight;
    const scrollTop = target.scrollTop;
    const clientHieght = target.clientHeight;

    if (scrollTop + clientHieght >= scrollHeight - 50 && maxNumber < allMenu.current.length) {
      setMaxNumber((number) => number + DISPLAY_INTERVAL);
    }
  };

  const throttleOnScroll = useThrottle<[React.UIEvent<HTMLDivElement>]>(onScroll, 300);

์œ„์— callback์œผ๋กœ ๋„˜๊ฒจ์ค„ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ด์ค€๋‹ค.

๊ทธ๋ฆฌ๊ณ  useThrottle์„ ์‹คํ–‰ํ•ด์„œ throttle์ด ์ ์šฉ๋œ ํ•จ์ˆ˜๋ฅผ ๋ฐ›์œผ๋ฉด ๋œ๋‹ค. ์ค‘์š”ํ•œ ๊ฒƒ์€ T์— ๋“ค์–ด๊ฐˆ ํƒ€์ž…์ด๋‹ค. callback์œผ๋กœ ๋„˜๊ฒจ์ค„ ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž… ์ˆœ์„œ๋Œ€๋กœ ( ex)<[type1, type2] ์ด๋Ÿฐ์‹) ์ ์–ด์ฃผ์–ด์•ผํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋ฐ˜ํ™˜๋œ throttleOnScroll ํ•จ์ˆ˜์—์„œ๋„ ํƒ€์ž… ์ถ”๋ก ์ด ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.