본문 바로가기

Web.d

[React][lodash/debounce] debounce 와 throttling 구현하기

반응형

디바운스(debounce)란?

연이어 호출되는 함수들 중 마지막 함수만 호출하도록 하는 것

첫 함수를 호출하고 일정한 시간 후까지 연이어 호출되는 함수를 무시되는 것이 아니라, 가장 마지막 함수를 호출하고 일정한 시간 후까지 호출이 안 되면 그 함수를 실행시킨다

 

디바운스

 

vs 쓰로틀링(throttling)

마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 하는 것

몇 밀리초에 한 번씩만 실행되게 제한을 두는 것

 

쓰로틀링

 

이는 아래에서 소개하는 debounce의 leading 옵션 기능과 같고,

스크롤이 바닥에 닿을 때마다 실행하는 함수 등에 사용할 수 있다

 

사용 문법

 

**_.debounce(func, [wait=0], [options={}])**

// Avoid costly calculations while the window size is in flux.
jQuery(window).on('resize', _.debounce(calculateLayout, 150));
 
// Invoke `sendMail` when clicked, debouncing subsequent calls.
jQuery(element).on('click', _.debounce(sendMail, 300, {
  'leading': true,
  'trailing': false
}));
 
// Ensure `batchLog` is invoked once after 1 second of debounced calls.
var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
var source = new EventSource('/stream');
jQuery(source).on('message', debounced);
 
// Cancel the trailing debounced invocation.
jQuery(window).on('popstate', debounced.cancel);

 

  1. func (Function): The function to debounce.
  2. [wait=0] (number): The number of milliseconds to delay.
  3. [options={}] (Object): The options object.
  4. [options.leading=false] (boolean): Specify invoking on the leading edge of the timeout.
  5. [options.maxWait] (number): The maximum time func is allowed to be delayed before it's invoked.
  6. [options.trailing=true] (boolean): Specify invoking on the trailing edge of the timeout.

 

여기서, leading과 trailing이 true라면, throttle 기능과 같다고 알 수 있다

lodash/throttle.js at 4.8.0-npm · lodash/lodash

 

GitHub - lodash/lodash: A modern JavaScript utility library delivering modularity, performance, & extras.

A modern JavaScript utility library delivering modularity, performance, & extras. - GitHub - lodash/lodash: A modern JavaScript utility library delivering modularity, performance, & extras.

github.com

 

사용법

 

yarn add lodash
yarn add @types/lodash

 

import _, { debounce } from "lodash"

const debouncingQuery = debounce((searchingText: string) => setQuery(searchingText), 500);

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  const text = e.currentTarget.value;

  debouncingQuery(text);
};

 

debounce 를 라이브러리 사용 없이 간단하게 직접 구현한 코드는 다음과 같다

 

const $input = document.querySelector("#input");
const $app = document.querySelector("#app");

const callAjaxRequest = (e) => {
  ...
};

const debounce = (func) => {
  let timer;
  
  return (e) => {
    if(timer) {
      clearTimeout(timer);
    }
    
    timer = setTimeout(func(e), 500);
  };
};

$input.addEventListener("input", debounce(callAjaxRequest));

 

아래는 React에 적용하여 useEffect 훅에 사용한 코드이다

 

function SearchInput() {
  const [query, setQuery] = useState('');
  const [tmpQuery, setTmpQuery] = useState(query);
  const handleChange = (e: ChangeEvent<HTMLInputElement>) => setTmpQuery(e.target.value);

  useEffect(() => {
    const debounce = setTimeout(() => {
      return setQuery(tmpQuery);
    }, 300); 				//->setTimeout 설정
    return () => clearTimeout(debounce); //->clearTimeout 바로 타이머 제거
  }, [tmpQuery]);			//->결국 마지막 이벤트에만 setTimeout이 실행됨

  ~

 

이를 커스텀 훅으로 작성하면 다음과 같겠다

 

function useDebounce<T>(defaultValue: T) {
  // query: 200ms 동안 모인 글자, 최종적으로 사용될 변수
  const [query, setQuery] = useState<T>(defaultValue);
  // debounceQuery: input value로 사용되면서 변화가 감지될 state
  const [debounceQuery, setDebounceQuery] = useState<T>(defaultValue);

  useEffect(() => {
    const debounceTimeout = setTimeout(() => {
      return setQuery(debounceQuery);
    }, 200);

    return () => clearTimeout(debounceTimeout);
  }, [debounceQuery]);

  return { query, debounceQuery, setDebounceQuery };
}

 

다음은 throttle 에 대한 직접 구현 코드이다

 

function SearchResult({ query }: searchResultProp) {
  const [page, setPage] = useState(1);
  const [result, setResult] = useState<Array<any>>([]);
  const [throttle, setThrottle] = useState(false);

  const handleScroll = () => {
    if (throttle) return;
    if (!throttle) {
      setThrottle(true);
      setTimeout(async () => {
        setPage((page) => page + 1);
        setThrottle(false);
      }, 300);
    }
  };

  ~

 


Lodash Documentation

 

Lodash Documentation

_(value) source Creates a lodash object which wraps value to enable implicit method chain sequences. Methods that operate on and return arrays, collections, and functions can be chained together. Methods that retrieve a single value or may return a primiti

lodash.com

Debouncing and Throttling Explained Through Examples | CSS-Tricks

 

Debouncing and Throttling Explained Through Examples | CSS-Tricks

The following is a guest post by David Corbacho, a front end engineer in London. We've broached this topic before, but this time, David is going to drive the

css-tricks.com

lodash/debounce.js at 4.8.0-npm · lodash/lodash

https://youtu.be/By49qqkzmzA

 

반응형