반응형
디바운스(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
사용법
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);
}
};
~
Debouncing and Throttling Explained Through Examples | CSS-Tricks
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 |