
우리가 검색 인풋에 단어를 입력하면 입력되는 글자가 변경됨에 따라 값 변경 함수가 계속해서 호출되게 된다. 이렇게 잦은 값 변경이 일어나거나 혹은 연결된 API가 있는 경우 불필요한 렌더링 등으로 성능 저하가 일어나기 쉽다. 그래서 값 변경 사이에 일정한 시간 텀을 두어 연속적인 이벤트 발생을 하나로 처리하는 방식이 debounce 방식이다.
상품을 검색하는 input을 만들었다. 이 때 onChange에 따라 감지되는 모든 값을 함수에 전달하는 코드를 쓰게 되면 불필요한 렌더링이 많이 일어나게 된다.

이렇게 모든 입력이 감지되기 때문이다. 그래서 setTimeout을 사용해서 debounce 함수를 만들었다.
import { useEffect, useState } from "react";
export const useDebounce = (value: string, dealy = 100) => {
const [valueState, setValueState] = useState<string>(value);
useEffect(() => {
let timeout = setTimeout(() => {
setValueState(value);
}, dealy);
return () => {
clearTimeout(timeout);
};
}, [value, dealy]);
return valueState;
};
이 debounce 함수를 hook 으로 만들어서 컴포넌트에 불러와 사용해줬다.
const [textVal, setTextVal] = useState<string>(searchVal || "");
// hook 을 useDebounce로 호출해서 사용
const debouncedText = useDebounce(textVal, 300);
useEffect(() => {
// 입력된 textVal 값을 검색할 때 debounce 적용해서 setInput으로 넘기기
setInput(debouncedText);
}, [debouncedText, setInput]);
const handleTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setTextVal(() => e.target.value);
};
// 중략
return (
<input
placeholder={placeholder}
onChange={handleTextChange}
onKeyDown={handleEnterKey}
value={textVal}
autoFocus={focus}
/>
);
이렇게 코드를 작성해서 300 인터벌 타임을 준 결과,

이렇게 확연한 차이를 보였다. (조금 원활한 검색을 위해 100으로 사용했다.)
javascript에서 debounce를 사용할 때 유용한 라이브러리 중 하나가 Lodash 이다. 사실 평소에 라이브러리 검색을 잘 하지 않고 직접 만들어보는 편이라 있는 줄 몰랐는데, 면접 때 Lodash를 왜 사용하지 않았는지 물어봐주셔서 알게 되었다.
# npm 설치하기
npm i --save lodash
import debounce from "lodash/debounce";
const debouncedText = useCallback(
debounce((q) => setInput(q), 300),
[]
);
const handleTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setTextVal(() => e.target.value);
// 타이핑 끝나면 호출함
debouncedText(e.target.value)
};
이벤트가 끝나고 함수를 실행하는 debounce와 달리 이벤트 실행 후 일정 시간을 기다려서 함수를 한 번만 작동하게 하는 throttle이 있다. 이전에 프로젝트를 하면서 버튼 클릭 후 api 응답이 오기 전에 버튼을 계속 눌러서 계속 api를 호출하는 문제가 있었는데, 이 경우를 해결할 수 있는 방법을 알게되어 수정해볼 수 있을 것 같다.