디바운싱(Debouncing) : 연이어 발생한 이벤트를 하나의 그룹으로 묶어서 처리하는 방식으로, 주로 그룹에서 마지막, 혹은 처음에 처리된 함수를 처리하는 방식으로 사용되곤 한다.
useEffect(() => {
setFormIsValid(
enteredPassword.trim().length > 6 && enteredEmail.includes("@")
);
}, [enteredEmail, enteredPassword]);
위와 같이 enteredEmail, enteredPassword를 의존성 배열에 추가하여, 변화가 있을 때마다 formIsValid의 값을 변화시킨다고 했을 때에는 위와같이 useEffect를 사용하면 큰 문제가 되지 않을 것이다.
하지만 백엔드 서버와 통신하는 코드가 있다고 가정하면, 의존성 배열의 state들이 변화가 있을 때마다 네트워크 요청을 보낼 것이고, 이는 불필요한 네트워크 트래픽을 만든다.
따라서 최상단 정의대로 간단한 디바운싱을 구현하여, 마지막에 함수를 처리해보도록 하자.
useEffect(() => {
setTimeout(() => {
console.log("checking form validity!");
setFormIsValid(
enteredPassword.trim().length > 6 && enteredEmail.includes("@")
);
}, 500);
}, [enteredEmail, enteredPassword]);
위와 같이 사용한다면 8번의 타이핑을 했을 때
500ms 후 8번의 코드실행이 나타난다.
서버 통신이라고 가정한다면 8번의 실행은... 불필요하다.
useEffect(() => {
setTimeout(() => {
console.log("checking form validity!");
setFormIsValid(
enteredPassword.trim().length > 6 && enteredEmail.includes("@")
);
}, 500);
return () => {
console.log("CLEANUP");
};
}, [enteredEmail, enteredPassword]);
return문에 CLEANUP을 출력하는 익명함수를 추가했다.(기명 함수도 물론 가능.)
첫번째 이펙트가 실행되기 전에는 CLEANUP이 출력되지 않는다.
11번의 타이핑이 있으면 첫번째 이펙트가 실행되기 전에 11번 출력된다.
useEffect(() => {
const identifier = setTimeout(() => {
console.log("checking form validity!");
setFormIsValid(
enteredPassword.trim().length > 6 && enteredEmail.includes("@")
);
}, 500);
return () => {
console.log("CLEANUP");
clearTimeout(identifier);
};
}, [enteredEmail, enteredPassword]);
identifier라는 함수를 만들고 cleanup함수에서 clearTimeout을 시켜준다.
첫번째 이펙트는 결국 한번만 실행되고, 서버와 통신하는 코드라면 한번만 실행하여 불필요한 네트워크 트래픽을 줄일 수 있게 되었다.
참고로 의존성 배열이 빈배열이면 cleanup함수는 dom에서 컴포넌트(useEffect를 사용하는 컴포넌트)가 제거 될때 실행된다.
현재 실무에서는 서버와 통신하는 useEffect를 생성하여 의존성배열에 빈배열을 두고 컴포넌트 렌더시 한번만 실행하게 하고 있다.
그외 다른 state들을 조작하는 useEffect들은 새로 useEffect훅을 사용하여 처리하고 있는데, 디바운싱을 잘 활용하면 여러개의 useEffect들을 만들지 않고 보다 깔끔하게 처리 할 수 있을 것 같다.
쓰로틀링(throttling) : 마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 하는 것
몇 밀리초에 한 번씩만 실행되게 제한을 두는 것
이라는 개념도 있는데, 스크롤 이벤트에 주로 달아준다.
const handleScroll = () => {
if (throttle) return; //throttle이라는 state를 미리 선언해준다.
if (!throttle) {
setThrottle(true);
setTimeout(() => {
console.log("throttle");
setThrottle(false);
}, 300);
}
};
위와 같은 함수를 scroll이벤트에 달아주면
throttle이 false일 때 setTimeout함수가 실행되면서 throttle을 true로 바꿔주고 throttle이 true일 때는 return으로 함수를 종료시킬 수 있다.
그래서 throttle이 true일 때 실행될 함수를 300ms마다 실행할 수 있다.