Debounce란?
- Debounce는 함수를 여러번호출하고 마지막 호출에서 일정 시간이 지난 후 해당 함수의 기능이 동작하는 기법
- Debounce는 호출 시 지정된 시간 이후 호출된 가장 마지막 이벤트만 실행되는 기술
- Debounce 함수는 lodash의 debounce 함수를 사용할 수 있음
예를 들어 검색창에 "google"을 검색하는 경우 6번의 api 요청을 한다 → 비효율
Debounce를 사용하는 경우 함수는 6번 호출되지만 일정 시간이 지난 후 마지막 호출에서 api 요청을 함
api 호출 횟수가 5번에서 1번으로 감소 → 효율
scroll, resize, input, mousemove 와 같은 이벤트는 짧은 시간 간격으로 연속해서 발생
이러한 이벤트에 바인딩한 이벤트 핸들러는 과도하게 호출되어 성능에 문제를 일으킬 수 있음
lodash란?
- lodash는 자바스크립트의 인기 라이브러리
- debounce나 throttle처럼 구현하기 번거로운 함수들을 제공
- throttle : 지정된 시간 동안 함수가 최대 한 번만 호출되도록 함수 호출 최대 횟수를 조절하는 방법
Debounce | Throttle | |
정의 | 짧은 간격으로 연속된 이벤트가 발생하면 이밴트 핸들러를 호출하지 않다가 일정 시간이 경과한 이후 한 번만 호출합니다. | 짧은 간격으로 이벤트가 연속으로 발생하더라도 일정 시간 간격으로 이벤트 핸들러가 최대 한 번만 호출되도록 합니다. |
사용 | 일정 시간 동안 이벤트가 더 이상 발생하지 않으면 이벤트 핸들러가 한 번만 호출되는 디바운스는 resize 이벤트나 input 요소에 입력된 값으로 ajax 요청하는 입력 필드 자동완성, 버튼 중복 클릭 방지 처리에 유용하기 쓰입니다. | 연속해서 발생하는 이벤트를 그룹화해서 일정 시간 간격으로 이벤트 핸들러를 호출하는 throttle은 scroll 이벤트처리나 무한 스크롤 UI구현 등에 유용하게 사용됩니다. |
예시 | 당신이 엘리베이터 안에 있다고 상상해보자. 문이 닫히기 시작하고 갑자기 다른 사람이 타려고 한다면 엘리베이터가 층으로 이동하는 기능을 시작하지 않아서 문이 다시 열리게 된다. 그리고 또 다른 사람에 의해 층의 이동 변경 기능이 일어나게 된다. 즉, 엘리베이터는 기능을 지연시키고 있지만(층간 이동), 자원을 최적화하게 됨. |
특성 자체가 실행 횟수에 제한을 거는 것이기 때문에 일반적으로 성능 문제 때문에 많이 사용. 스크롤을 올리거나 내릴 때 scroll 이벤트 핸들러 경우에 매우 많이 발생한다. scroll 이벤트가 발생할 때 뭔가 복잡한 작업을 하도록 설정했다면 매우 빈번하게 실행되기 때문에 큰 버퍼링이 걸릴 지도 모른다. 그럴 때 throttle을 사용할 수 있음. 몇 초에 한 번, 또는 몇 밀리초에 한 번씩만 실행되게 제한을 두는 것 |
결론 | 연이어 호출되는 함수들 중 마지막 함수(또는 제일 처음)만 호출하도록 하는 것 | 이벤트를 일정한 주기마다 발생하도록 하는 기술 → 마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 하는 것 |
[수정 전 코드]
const handleDeviceChange = useCallback(
(value: string | React.ChangeEvent<HTMLInputElement>) => {
if (typeof value === "string") {
setShoppingValue(value);
dispatch(updateInputValues({ ...inputValues, [category]: value }));
}
},
[dispatch, inputValues, category]
);
[debounce 적용 후 코드]
import { debounce } from "lodash";
...
const handleDelayChange = useMemo(
() =>
debounce((value: string | React.ChangeEvent<HTMLInputElement>) => {
dispatch(updateInputValues({ ...inputValues, [category]: value }));
}, 300),
[category, dispatch, inputValues]
);
const handleDeviceChange = useCallback(
(value: string | React.ChangeEvent<HTMLInputElement>) => {
if (typeof value === "string") {
setShoppingValue(value);
handleDelayChange(value);
}
},
[handleDelayChange]
);
* useCallback과 debounce를 같이 쓸 경우
const handleDelayChange = useCallback(
debounce((value: string | React.ChangeEvent<HTMLInputElement>) => {
dispatch(updateInputValues({ ...inputValues, [category]: value }));
console.log(value);
}, 300),
[dispatch]
);
처음에는 debounce와 useCallback을 함께 사용하였고
다음과 같은 ESLint 경고가 떴다.
React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead.(react-hooks/exhausted-deps)
useCallback안에 lodash의 throttle이나 debounce로 함수를 감싼 형태일 때 이러한 ESLint 경고를 낸다.
해결방안은 useMemo를 사용해 수정하면 된다.
const handleDelayChange = useMemo(
() =>
debounce((value: string | React.ChangeEvent<HTMLInputElement>) => {
dispatch(updateInputValues({ ...inputValues, [category]: value }));
}, 300),
[category, dispatch, inputValues]
);
참고: https://kyleshevlin.com/debounce-and-throttle-callbacks-with-react-hooks
'React' 카테고리의 다른 글
[React] redux (0) | 2023.10.11 |
---|---|
[React] 리덕스 (1) | 2023.06.01 |
[React] 백엔드 프로그래밍 : Node.js의 Koa 프레임워크 (0) | 2023.05.03 |
[React] 서버 사이드 렌더링 (0) | 2023.05.02 |
[React] 코드 스플리팅 (0) | 2023.05.01 |