[ React ] Throttle (쓰로틀링) / Custom Hook

혜빈·2024년 7월 28일
0

REACT 보충개념

목록 보기
45/48

Throttle

  • 온라인 게임에서 스킬 = 함수 라고 생각하기

  • 함수가 너무 자주 호출될때 그 횟수를 제한하는 기술

  • 만약 무거운 작업을 하는 함수라면 상당한 CPU 사용 혹은 서버 비용이 발생함
    -> 자원 방지를 위해서 지나치게 자주 호출되는 것을 방지할 필요가 있음

  • 즉, 쓰로틀링은 함수가 한번 호출되면 일정 시간이 지나기 전에 다시 호출되지 않도록 막는것임
    (게임에서 쿨타임 끝나기 전에 다시 스킬 사용 못하는 상황과 비슷)

실제 코드 구현

  • 로또 번호 생성기 만들기

Throttle 사용하기 전 코드

ThrottleHook

import { useState } from "react";
import "../ThrottleHook.css";

function hackLottoNumbers() {
  console.log("행운의 로또 번호 생성중🍀");
  const lottoNumbers = [];
  for (let i = 0; i < 6; i++) {
    const number = Math.floor(Math.random() * 45) + 1;
    lottoNumbers.push(number);
  }
  return lottoNumbers;
}

function ThrottleHook() {
  const [lottoNumbers, setLottoNumbers] = useState([0, 0, 0, 0, 0, 0]);

  const handleClick = () => {
    const result = hackLottoNumbers();
    setLottoNumbers(result);
  };

  return (
    <div className="container">
      <h1 className="title">로또 번호 맞추자~!</h1>
      <button className="button" onClick={handleClick}>
        번호 맞추기
      </button>
      <div className="numbers">
        {lottoNumbers.map((number, idx) => (
          <span key={idx} className="number">
            {number}
          </span>
        ))}
      </div>
    </div>
  );
}

export default ThrottleHook;

  • 만약 사용자가 번호 맞추기 버튼을 계속 클릭하게 되면 hackLottoNumbers 함수가 엄청 많이 호출됨 -> 비용과 리소스 낭비
    - 해결 방법 : 사용자가 많이 눌러도 함수가 지나치게 자주 호출되지 않도록 호출 횟수를 제한하기
    -> 함수 호출 사이에 쿨타임 넣기 -> Throttle 사용

  • 함수가 한 번 호출되면 1초동안 호출되지 못하도록 제한하기


Throttle 사용 후 코드

  1. 사용자가 버튼을 클릭해서 hackLottoNumbers 함수가 호출되면 함수가 호출된 시간 기록하기
  2. 사용자가 버튼을 한 번 더 누를 때 그 시간과 이전 기록 시간을 비교하기
  3. 만약 이전 호출로부터 1초가 지나지 않았다면 -> 무시
    1초가 지났다면 -> 함수가 한 번 더 호출될 수 있도록 허락하기

  • 함수가 호출된 시간을 기록하기 위해 lastRun 변수 생성하고 useRef사용하기
    (state가 update 될 때 기록한 시간값이 초기화 되는 것을 막기 위해 useRef사용)

  • 사용자가 버튼 클릭한 시간에서 lastRun 빼서 timeElapsed 변수에 담아주고 조건문 작성해주기

import { useState, useRef } from "react";
import "../ThrottleHook.css";

function hackLottoNumbers() {
  console.log("행운의 로또 번호 생성중🍀");
  const lottoNumbers = [];
  for (let i = 0; i < 6; i++) {
    const number = Math.floor(Math.random() * 45) + 1;
    lottoNumbers.push(number);
  }
  return lottoNumbers;
}

function ThrottleHook() {
  const [lottoNumbers, setLottoNumbers] = useState([0, 0, 0, 0, 0, 0]);

  // state가 update 될 때 기록한 시간값이 초기화 되는 것을 막기 위해 useRef사용
  const lastRun = useRef(Date.now());

  const handleClick = () => {
    const timeElapsed = Date.now() - lastRun.current;

    if (timeElapsed >= 1000) {
      const result = hackLottoNumbers();
      setLottoNumbers(result);
      lastRun.current = Date.now();
    }
  };

  return (
    <div className="container">
      <h1 className="title">로또 번호 맞추자~!</h1>
      <button className="button" onClick={handleClick}>
        번호 맞추기
      </button>
      <div className="numbers">
        {lottoNumbers.map((number, idx) => (
          <span key={idx} className="number">
            {number}
          </span>
        ))}
      </div>
    </div>
  );
}

export default ThrottleHook;

  • 연속으로 여러번 클릭해도 console은 한 번만 출력됨(함수가 1초에 한 번만 호출됨)

Custom Hook으로 만들기

  • 코드 중복 없이 여러 컴포넌트에서 재사용 하기 위해서 custom hook으로 만들기

ThrottleHook

import { useState } from "react";
import { useThrottle } from "../hooks/useThrottle";
import "../ThrottleHook.css";

function hackLottoNumbers() {
  console.log("행운의 로또 번호 생성중🍀");
  const lottoNumbers = [];
  for (let i = 0; i < 6; i++) {
    const number = Math.floor(Math.random() * 45) + 1;
    lottoNumbers.push(number);
  }
  return lottoNumbers;
}

function ThrottleHook() {
  const [lottoNumbers, setLottoNumbers] = useState([0, 0, 0, 0, 0, 0]);

  const handleClick = useThrottle(() => {
    const result = hackLottoNumbers();
    setLottoNumbers(result);
  }, 1000);

  return (
    <div className="container">
      <h1 className="title">로또 번호 맞추자~!</h1>
      <button className="button" onClick={handleClick}>
        번호 맞추기
      </button>
      <div className="numbers">
        {lottoNumbers.map((number, idx) => (
          <span key={idx} className="number">
            {number}
          </span>
        ))}
      </div>
    </div>
  );
}

export default ThrottleHook;

useThrottle

import { useRef } from "react";

// delay - 쿨타임
export function useThrottle(callback, delay) {
  // state가 update 될 때 기록한 시간값이 초기화 되는 것을 막기 위해 useRef사용
  const lastRun = useRef(Date.now());
  return () => {
    const timeElapsed = Date.now() - lastRun.current;

    if (timeElapsed >= delay) {
      callback();
      lastRun.current = Date.now();
    }
  };
}

  • 여러번 눌러도 1초에 한번씩만 함수가 실행되도록 잘 작동이 됨
profile
최강 개발자를 꿈꾸는 병아리

0개의 댓글