디바운스(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);
- func (Function): The function to debounce.
- [wait=0] (number): The number of milliseconds to delay.
- [options={}] (Object): The options object.
- [options.leading=false] (boolean): Specify invoking on the leading edge of the timeout.
- [options.maxWait] (number): The maximum time func is allowed to be delayed before it's invoked.
- [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
_(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
'Web.d' 카테고리의 다른 글
[React][framer-motion] framer-motion Animation Library (0) | 2022.02.08 |
---|---|
[React] map 함수에 key 값이 필요한 이유 (재조정; Reconciliation) (0) | 2022.02.02 |
[React][Context] Prop drilling 과 useContext (1/2) (0) | 2021.12.30 |
[React][react-router] react-router-dom v6 (Upgrading from v5) (0) | 2021.11.12 |
[React][react-router] react-router-dom v5 (0) | 2021.11.02 |