오늘도 어김없이 회사에서 열심히 코드를 보고 또 보다가... Slider 컴포넌트 코드가 눈에 띄어 열심히 톺아보았습니다.
그런데 한 가지 불편한 점을 발견하게 되는데요👀👀👀
바로 슬라이더를 움직일 때마다 함수가 계속 호출되는 것입니다.
만약 현재 값이 1인데 100으로 이동한다면 함수가 100번이나 호출되어야 한다는 점!!
지금부터 이 부분을 개선하는 방법을 함께 알아봅시다.
(회사 코드를 그대로 가져올 수 없어서 MUI 예시로 들겠습니다)
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를 사용하면 됩니다.
저처럼 디바운스라는 개념이 낯선 분들을 위해 간략하게 정리하자면,
연속해서 같은 행동을 취해도 오직 한 번만 함수를 실행하는 것입니다.
const debounce = (func, timeout = 300) => {
let timer;
return (...args) => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
};
debounce
는 위와 같이 작성할 수 있습니다.
func
와 디바운스 시간 간격인 timeout
을 매개변수로 받고 timer
를 초기화한다. timer
에 값이 존재하는 경우, 즉 이전에 예약된 함수 호출이 있으면 취소한다. return (
<Box sx={{ width: 300 }}>
<Slider value={value} onChange={debounce(handleChange, 20)} />
</Box>
);
onChange
에 debounce
함수를 적용하여 결과를 확인해봅시다.
20ms 사이에 이동한 구간에서는 onChange
함수가 호출되지 않는 것을 확인할 수 있다.
사용자 입장에서 슬라이드가 20ms만큼 느리게 움직여 보이는 단점이 있지만, 성능을 개선하는 목표는 달성하였다 😋
debounce
를 자바스크립트로 구현할 수도 있지만 라이브러리를 사용하여 더욱 쉽게 구현할 수 있다.
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/
https://mui.com/material-ui/react-slider/
https://lodash.com/