아래 사진처럼 검색 키워드가 변경될 때 마다 불필요하게 네트워크 요청을 계속 보내는 모습입니다.
개인 프로젝트 수준에서는 무시해도 될 수준이지만 실제 현업에서는 이런 불필요한 요청들이 모이면 비용 문제가 은근 클거 같아서
이번 기회에 개념만 알고있던 디바운스
를 이용해서 최적화를 해보았습니다.
...
const Component = () => {
const [keyword, setKeyword] = useState('');
const {
data: users,
isLoading,
error,
} = useSWR<User[]>(`/api/search/${keyword}`);
...
}
디바운스와 쓰로틀은 특정 함수의 실행이 반복적으로 실행될 때 네트워크 또는 Cpu등의 과부화를 막기위한 프로그래밍 기법입니다.
다수의 호출로 인한 성능저하를 방지하기 위해 호출 수 자체를 줄이면 됩니다.
Debounce
는 다수의 호출을 묶는 것이다.
100번의 요청이 단기간에 몰릴 경우 마지막 요청만을 실행한다고 생각하면 되고,
Throttle
은 다수의 호출에 간격을 두는 것 이다.
PC에 관심이 있는 사람이라면 쓰로틀링에 대해 많이 알고있을텐데 똑같은 개념입니다.
CPU의 발열이 심해지면 기기 보호를 위해 CPU 클럭수를 급격히 낮추는 것을 의미합니다.
아래 링크에서 디바운싱과 쓰로틀링을 직접 체험해보면 바로 이해가 갈 개념입니다
https://redd.one/blog/debounce-vs-throttle
인자로 받은 value를 디바운싱한 뒤 리턴해주는 커스텀 훅
// @/hooks/useDebounce.ts
import { useState, useEffect } from 'react';
const useDebounce = (value: string, delay: number = 500) => {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const handler = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debounced;
};
export default useDebounce;
이제 디바운싱 한 검색 키워드를 SWR 인자로 전달한다.
const Component = () => {
const [keyword, setKeyword] = useState('');
const debouncedKeyword = useDebounce(keyword);
const {
data: users,
isLoading,
error,
} = useSWR<User[]>(`/api/search/${debouncedKeyword}`);
...
}
keyword가 변경되면서 리랜더링이 발생할 때 useSWR가 다시 호출되어야 할 것 같다고 생각할 수도 있는데,
해당 부분은 SWR이 알아서 내부적으로 캐싱 된 값을 사용하기 때문에 중복 네트워크 요청을 하지 않습니다!
Debounce는 다수의 호출을 묶고 끝날 때까지 기다렸다가 시작되고, Throttle은 다수의 호출의 일정 간격으로 계속 실행한다는 점이 다르다.
따라서 확실한 최적화를 위해서는 Debounce로 함수를 한 번만 실행되도록 하는 것이 효과적일 것 같지만,
유저가 즉각적인 결과를 기대하는 기능에 있어서는 Throttle을 사용하여 UX를 신경쓰는 것도 좋은 방법같다.