일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- Throttle
- RN아키텍쳐
- react-native
- private-access-to-photos
- hydration mismatch
- React-Native업데이트
- react native
- RN새로운아키텍쳐
- motion.div
- react animation
- await
- async
- promise.all
- CS
- Swift
- react
- rn
- axios
- Hash-table
- react-native-permissions
- react-native-image-picker
- animation
- RN업데이트
- javascript
- 비동기
- ios
- named type
- debounce
- Promise
- no-permission-handler-detected
- Today
- Total
하루살이 개발일지
React) Debounce와 Throttle의 개념과 예시 및 사용법 (+lodash) 본문
디바운스 & 스로틀이란 ?
scroll, resize, input, mousemove 같은 이벤트는 짧은 시간 간격으로 연속해서 발생함. 이러한 이벤트에 바인딩한 이벤트 핸들러는 과도하게 호출되어 성능에 문제를 일으킬 수 있음. 디바운스와 스로틀은 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화하여 과도한 이벤트 핸들러의 호출을 방지하는 프로그래밍 기법
디바운스
[디바운스란?]
- 짧은 시간 간격으로 이벤트 연속해 발생하면 이벤트 핸들러를 호출하지 않다가 일정 시간이 경과한 이후에 이벤트 핸들러가 한 번만 호출되도록 하는 것
- 즉 짧은 시간 간격으로 발생하는 이벤트를 그룹화하여 마지막에 한 번만 이벤트 핸들러가 호출되도록 함
[사용 예시]
- 텍스트 입력 필드에서 input 이벤트가 짧은 시간 간격으로 연속해서 발생하는 경우
- input 이벤트는 사용자가 입력할 때마다 연속해서 발생
- 만약 input 이벤트 핸들러에서 사용자가 입력 필드에 요청한 값으로 ajax 요청과 같은 무거운 처리 수행한다면 사용자가 입력을 완료 못해도 ajax 요청이 전송될 것
- 이는 서버에도 부담가는 불필요한 처리 ⇒ 사용자가 입력 완료했을 때 한 번만 ajax 요청 전송하는 것이 바람직
- 사용자가 입력 완료했는지 정확히 알 수 없으므로 일정 시간 동안 텍스트 입력 필드에 값을 입력하지 않으면 입력이 완료된 것으로 간주
- 이를 위해 debounce 함수를 활용할 수 있음
- delay보다 짧은 시간 간격으로 이벤트 발생 시 이전 타이머를 취소하고 새로운 타이머를 재설정
- 즉 delay보다 짧은 간격으로 이벤트 연속 발생 시 debounce 함수의 첫 번째 인자인 콜백 함수를 호출하지 않다가, delay동안 input 이벤트가 더 이상 발생하지 않으면 한 번만 호출됨
[주로 사용할 때]
- resize 이벤트 처리
- input 요소에 입력된 값으로 ajax 요청하는 입력 필드 자동완성 UI 구현
- 버튼 중복 클릭 방지 처리
실무에서는 Underscore의 debounce 함수나 Lodash의 debounce 함수를 사용하는 것을 권장
스로틀
[쓰로틀이란?]
- 짧은 시간 간격으로 이벤트 연속해 발생하더라도 일정 시간 간격으로 이벤트 핸들러가 최대 한 번만 호출되도록 하는 것
- 즉 짧은 시간 간격으로 연속해 발생하는 이벤트를 그룹화해서 일정 시간 단위로 이벤트 핸들러가 호출되도록 호출 주기를 만드는 것
[주로 사용할 때]
- scroll 이벤트 처리
- 무한 스크롤 UI 구현
마찬가지로 실무에서는 Underscore의 throttle 함수나 Lodash의 throttle 함수를 사용하는 것이 권장됨
Debounce의 예시
import { useCallback, useEffect, useState } from "react";
import _ from "lodash";
export const Count = () => {
const [count, setCount] = useState(0);
// Debounce 사용 시
const debouncedCountUp = useCallback(
_.debounce(() => setCount((prevCount) => prevCount + 1), 1000),
[]
);
const debouncedCountDown = useCallback(
_.debounce(() => setCount((prevCount) => prevCount - 1), 1000),
[]
);
// Debounce를 사용하지 않았을 때
// const countUp = () => setCount((prevCount) => prevCount + 1);
// const countDown = () => setCount((prevCount) => prevCount - 1);
useEffect(() => {
return () => {
debouncedCountUp.cancel();
debouncedCountDown.cancel();
};
}, []);
return (
<div>
<h2>Debounce</h2>
{/* Debounce를 사용했을 때 */}
<button onClick={debouncedCountUp}>Count Up</button>
<button onClick={debouncedCountDown}>Count Down</button>
{/* Debounce를 사용하지 않았을 때 */}
{/* <button onClick={countUp}>Count Up</button>
<button onClick={countDown}>Count Down</button> */}
<p>{count}</p>
</div>
);
};
CountUp 버튼과 CountDown 버튼을 아무리 많이 클릭해도 1000ms(=1초) 기다리지 않으면 count가 증가하거나 감소하지 않는다.
참고로 debounce나 throttle 함수를 사용하면 꼭 useEffect의 clean-up 함수(return 부분)로 감싸주어야 한다.
그 이유는 컴포넌트가 언마운트된 이후에도 두 함수에 의해 예약된 함수 호출이 존재하면, 그 함수는 계속해서 실행될 수 있기 때문이다.
이러한 상황은 메모리 누수로 이어질 수 있다.
만약에 컴포넌트가 언마운트되었는데도 컴포넌트의 상태를 변경하는 작업이 이루어진다면 (이 경우에는 debounce나 throttle) 이는 Can't perform a React state update on an unmounted component"와 같은 경고를 일으킬 수 있다.
Throttle의 예시
import { useCallback, useEffect, useState } from "react";
import _ from "lodash";
export const Throttle = () => {
const [count, setCount] = useState(0);
// Throttle 사용 시
const throttledCountUp = useCallback(
_.throttle(() => setCount((prevCount) => prevCount + 1), 1000),
[]
);
const throttledCountDown = useCallback(
_.throttle(() => {
console.log(123);
setCount((prevCount) => prevCount - 1);
}, 1000),
[]
);
// Throttle를 사용하지 않았을 때
// const countUp = () => setCount(prevCount => prevCount + 1);
// const countDown = () => setCount(prevCount => prevCount - 1);
useEffect(() => {
return () => {
throttledCountUp.cancel();
throttledCountDown.cancel();
};
}, []);
return (
<div>
<h2>Throttle</h2>
<button onClick={throttledCountUp}>Count Up</button>
<button onClick={throttledCountDown}>Count Down</button>
{/* Throttle를 사용하지 않았을 때 */}
{/* <button onClick={countUp}>Count Up</button> */}
{/* <button onClick={countDown}>Count Down</button> */}
<p>{count}</p>
</div>
);
};
이제는 버튼을 아무리 많이 클릭해도 내가 설정한 시간(현재는 1000ms) 동안에는 최대 딱 1번만 카운트가 바뀐다.
나머지 기능은 debounce와 동일하다.
'웹개발 > React' 카테고리의 다른 글
Axios 비동기 통신 - get, post, delete, patch (0) | 2023.07.04 |
---|---|
Redux의 이해 : createSlice에서 reducer와 reducers의 차이 (0) | 2023.07.04 |
Redux란? (+Context API, Recoil과의 차이점) (0) | 2023.06.28 |
React에서 Debounce, Throttle이 작동하지 않는 이유 (0) | 2023.06.24 |
useMemo란? useMemo의 개념 및 실습 (0) | 2023.06.22 |