스크림도르의 성향 태그 추가 모달을 리팩토링하던 중 searchWord
라는 state의 onChange에 따라 전체 컴포넌트가 리랜더링되는 것을 확인했다.
최적화를 위해서 방법은 찾아봐야하는 상황. 이것저것 시도해보기 시작했다.
가장 먼저 들었던 생각이다. onChange 자체에 debounce를 걸어서 리랜더링의 횟수를 줄여보는 것은 어떨까한 것이다.
// before
<input onChange={(e) => setSearchWord(e.target.value)} />
// after
<input onChange={(e) => _.debounce(setSearchWord(e.target.value),1500)} />
요렇게 바꾸어 보았다.
잘 되는 것 같았지만 이내 이런 에러가 뜬다.
아니? 나는 함수를 넘겼다고 생각했는데?? 결과적으로는 아니었따.
//simple debounce implementation
const debounce = (fn, delay = 50) => {
let time;
return (...args) => {
clearTimeout(time);
time = setTimeout(() => fn(...args), delay);
};
};
debounce 함수는 간단하게 위와 같은 형태를 취하고 있다. 우리가 onChange에 넘긴 setSearchWord
는 undefined
를 return한다. 따라서, debounce함수는 자기가 받은 것이 함수 형태가 아니라고 생각하는 것이다.
이것저것 찾아보니 onChange자체에 debounce를 적용하려는 시도는 보이지 않았다. 혹시 내가 잘못된 방향으로 생각을 하고 있는 것 아닌가 하는 생각에 다른 검색을 해보니,
스택오버플로우에서 나랑 똑같은 질문을 한 글을 확인할 수 있었다.
결론적으로 react에서 controlled input을 관리하는 방법이니 별도의 컴포넌트로 분리하라는 답변... 생각해보면 당연한 거였는 이상한데에 꽂혀서 인지하지 못하고 있었다..
항상 react에서 throttle debounce 사용하는 방법이 헷갈린다..
throttle한 함수를 callback에 넣어두자..!
const handleTouchMove = _.throttle(e => {
console.log(e.touches[0]);
}, 1000);
const qwer = useCallback(handleTouchMove, [handleTouchMove]);
/* ... */
<ContainerHeader
ref={handle}
onTouchStart={handleTouchStart}
onTouchMove={qwer}
onTouchEnd={handleTouchEnd}
>
https://stackoverflow.com/questions/23123138/perform-debounce-in-react-js?page=1&tab=votes#tab-top
https://stackoverflow.com/questions/64820257/lodash-debounce-typeerror-expected-a-function-react