오늘도 어김없이 회사에서 열심히 코드를 보고 또 보다가... Slider 컴포넌트 코드가 눈에 띄어 열심히 톺아보았다. 그런데 한 가지 불편한 점을 발견하게 되었다 👀
바로 슬라이더를 움직일 때마다 함수가 계속 호출되는 것이다. 예를 들어 현재 값이 1인데 100으로 이동한다면 함수가 100번이나 호출되어야 한다는 점!
지금부터 이 부분을 개선하는 방법을 함께 알아보자.
🤔 Slider 움직일 때마다 리소스 소비.. 최선인가
슬라이더 컴포넌트에서 포인터를 좌우로 움직이면 값이 변하는 코드가 있다. 현재 값에서 다음 값으로 이동할 때 그 사이 트랙을 모두 지나는 것이 슬라이더의 핵심이다. 하지만 여기서 치명적인 단점을 발견할 수 있다.
export default function SliderExample() {
const [value, setValue] = useState(30);
const handleChange = (event, newValue) => {
console.log(newValue);
setValue(newValue);
};
return (
<Box sx={{ width: 300 }}>
<Slider value={value} onChange={handleChange} />
</Box>
);
}
숫자를 하나 지나갈 때마다 handleChange
함수가 호출되어 불필요한 리소스를 소비하는 것이다. 솔직히 중간 값은 자연스럽게 빼먹어도 될 것 같은데... 어떻게 해결할 수 있을까?
🤩 debounce로 최적화 해보자!
debounce를 사용하면 해결할 수 있다. 디바운스란 연속해서 같은 행동을 취해도 오직 한 번만 함수를 실행하는 것이다. 디바운스는 다음과 같이 작성할 수 있다.
실행 함수인
func
와 디바운스 시간 간격인timeout
을 매개변수로 받는 디바운스 함수를 생성한다.새로운 호출을 예약하는 데 사용할
timer
를 초기화한다.
timer
에 값이 존재하는 경우, 즉 이전에 예약된 함수 호출이 있으면 해당timer
를 삭제한다.
timeout
이 경과한 후 함수를 실행한다.
const debounce = (func, timeout = 300) => {
let timer;
return (...args) => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
};
onChange
에 debounce
함수를 적용하여 결과를 확인해보자.
return (
<Box sx={{ width: 300 }}>
<Slider value={value} onChange={debounce(handleChange, 20)} />
</Box>
);
20ms 사이에 이동한 구간에서는 onChange
함수가 호출되지 않는 것을 확인할 수 있다.
사용자 입장에서 슬라이드가 20ms만큼 느리게 움직여 보이는 단점이 있지만, 성능을 개선하는 목표는 달성하였다. 😋
🛠️ 직접 구현하기 귀찮으니 라이브러리를 써보자
디바운스를 자바스크립트로 구현할 수도 있지만 라이브러리를 사용하여 더욱 쉽게 구현할 수 있다.
npm i --save lodash
import { debounce } from "lodash";
export default function SliderExample() {
const [value, setValue] = useState(30);
const handleChange = (event, newValue) => {
console.log(newValue);
setValue(newValue);
};
return (
<Box sx={{ width: 300 }}>
<Slider value={value} onChange={debounce(handleChange, 20)} />
</Box>
);
}
정말 간단하다... 💨💨💨
마치며
가벼운 프로젝트에서는 고려할 필요가 없었지만, 인터렉티브한 요소가 많은 페이지에서는 불필요한 리소스를 최소화하는 방법을 고려할 필요가 있다.
나는 슬라이더에만 사용해보았지만 나중에 디바운스가 필요한 경우가 또 발견되면 반가울 것 같다!
레퍼런스
https://www.freecodecamp.org/news/javascript-debounce-example/
mui.com/material-ui/react-slider
lodash.com