debounce나 throttle이 원하는대로 동작하지 않을 때

권현경·2022년 8월 10일
0

https://rajeshnaroth.medium.com/using-throttle-and-debounce-in-a-react-function-component-5489fc3461b3
위 글을 참고하였습니다.

search 기능을 구현할 때 debounce를 사용하곤 하는데 원하는대로 동작하지 않을 때가 있었다.

const [keyword, setKeyword] = useState('');

const search = _.debounce((keyword: string) => {
	// search 로직
}, 500);

return <>
	<input onChange={(e)=>{
    	setKeyword(e.target.value);
        search(e.target.value);
    }}

</>

위와 같은 코드가 있다고 해보자. 내가 기대하는 바는 두루미를 검색할 때 ㄷ, 두, ㄹ, 루 이런식으로 검색되는 게 아니라 , 두루 이런 식으로 검색 되는 것이다. 그걸 기대하며 debounce를 사용했는데 왜인지 ㄷ, 두, ㄹ, 루 이런 식으로 하나하나 검색이 되었다.

그래서 이리저리 검색해봤더니 위 글을 찾을 수 있었다. 원인은 아래와 같았다.

Throttle and debounce works using window.setTimeout() behind the scenes. Every time the function component is evaluated, you are registering a fresh setTimeout callback.

throttle과 debounce는 window.setTimeOut()을 사용하여 동작하는데 컴포넌트가 *re-evaluation 될때마다 새로운 setTimeOut 콜백을 등록한다고 한다.

따라서 어떻게든 Debounced Callback에 대한 참조를 저장해야 한다. 방법은 두가지가 있는데 아래에 소개해보겠다.

*Re-evaluating Components 와 Re-Rendering DOM의 차이
Component는 props,state, 또는 context가 바뀔때마다 re-evaluate된다 vs DOM은 evaluation 사이에 변화가 있을 때 re-render된다.

해결방법

useRef

useRef()로부터 반환된 value는 re-evalutated 되지 않기 때문에 아래와 같이 구현하면 해결할 수 있다.

const [keyword, setKeyword] = useState('');

const search = useRef(_.debounce((keyword: string) => {
	// search 로직
}, 500)).current;

return <>
	<input onChange={(e)=>{
    	setKeyword(e.target.value);
        search(e.target.value);
    }}

</>

useCallback

useCallback도 마찬가지이다. 이게 current를 사용하지 않고 더 직관적이기 때문에 위보다 좀 더 깔끔한 방법같다.

const [keyword, setKeyword] = useState('');

const search = useCallback(_.debounce((keyword: string) => {
	// search 로직
}, 500),[]);

return <>
	<input onChange={(e)=>{
    	setKeyword(e.target.value);
        search(e.target.value);
    }}

</>
profile
프론트엔드 개발자

0개의 댓글