aotoyae

[React] Throttling & Debouncing : 과도한 이벤트 핸들러 호출 방지 본문

React

[React] Throttling & Debouncing : 과도한 이벤트 핸들러 호출 방지

aotoyae 2024. 2. 20. 18:56

 

 

💡 짧은 시간 간격으로 연속해서 이벤트가 발생했을 때 과도한 이벤트 핸들러 호출을 방지하는 기법

ex) 좋아요를 엄청 많이 누를 때 ~

 

✳️ Throttling : 주로 무한스크롤에 사용

게임 중 공격 버튼을 마구 누르는데 일정 시간 동안 한 발씩 발사될 때!! 쓰롤링이 실행 된 것이다.

1. Leading Edge     2. Trailing Edge     3.  Leading & Trailing edge

 

이렇게 짧은 시간 간격으로 연속해서 발생한 이벤트들을

일정시간 단위(delay)로 그룹화하여 처음 또는 마지막 이벤트 핸들러만 호출되도록 한다.

 

✳️ Debouncing : 주로 입력값 실시간 검색, 화면 resize 이벤트에 사용

전등 스위치 버튼 누르면 불이 깜빡이다가 켜지는 것! 디바운싱이 실행된 것이다.

출처: 자바스크립트 딥다이브

 

짧은 시간 간격으로 연속해서 이벤트가 발생하면

이벤트 핸들러를 호출하지 않다가 마지막 이벤트로부터 일정 시간(delay)이 경과한 후에 한 번만 호출하도록 한다.

 

👀 그럼 이제 사용해보자!

npm add react-router-dom

 

App.jsx

import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import Company from "./pages/Company";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/company" element={<Company />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

 

pages/Home.jsx

function Home() {
  let timerId = null;

  const throttle = (delay) => { // 쓰로틀
    if (timerId) { // timer 에 숫자가 있으면 그냥 리턴
      return;
    }
    console.log(`API 요청 실행: ${delay}ms 동안 추가 요쳥 안받아요.`);
    timerId = setTimeout(() => {
      console.log(`${delay}ms 지났으니 추가 요청 받아요.`);
      timerId = null;
    }, delay);
  };

  const debounce = (delay) => { // 디바운스
    if (timerId) { // timer 에 숫자가 있으면 초기화
      clearTimeout(timerId);
    }
    timerId = setTimeout(() => {
      console.log(`마지막 요청으로 부터 ${delay}ms가 지났으므로 API 요청 실행`);
    }, delay);
  };

  return (
    <div>
      <h1>Throttle & Debounce</h1>
      <h2>버튼 이벤트 예제</h2>
      <button onClick={() => throttle(2000)}>throttle</button>
      <button onClick={() => debounce(2000)}>debounce</button>
    </div>
  );
}

export default Home;

debounce : 2초 내에 버튼을 또 누르면 아예 실행되지 않고(timer 가 계속 초기화됨),
마지막 클릭(이벤트)만 인식하고 2초 뒤 실행

 

throttle : 실행하고 2초 동안(실행 중)은 또 눌러도 요청을 받지 않지만,

2초 뒤 다음 요청을 받는다.

 

💡 메모리 누수 관리 : useEffect()

페이지 이동 버튼을 추가했다.

<button onClick={() => {navigate("company");}}>
  페이지 이동
</button>

Home 페이지에서 throttle 을 실행하고 Company 페이지로 이동했는데,

그 전 페이지에서 요청한게 아직도 메모리에 남아있다.

 

  useEffect(() => {
    return () => { // 언마운트 시
      if (timerId) {
        clearTimeout(timerId);
      }
    };
  }, [timerId]);

 

🤓 useEffect 에 리턴으로 timerId 가 있으면(실행 중이면) clear 하라는 값을 넣어주면

페이지 이동 후 "2000ms 지났으니 추가 요청 받아요."  문구가 나오지 않는다.

 

 

 

🔗 https://kettanaito.com/blog/debounce-vs-throttle

 

Debounce vs Throttle: Definitive Visual Guide

A complete guide to learn the difference between debounce and throttle using visual examples. Never confuse the two again.

kettanaito.com