[React] Throttle, Debounce (feat. React Hook)

고병표·2022년 2월 3일
0

React.js

목록 보기
11/21

Throttle와 Debounce

Throttle

  • 스로틀링(Throttling)은 함수가 지정된 시간 동안 최대 한 번 호출되도록 하는 프로그래밍 방법입니다.
  • 스로틀링은 함수를 호출할 수 있는 최대 횟수를 조절합니다.
  • Ex) 10초마다 함수를 최대 한 번 호출

Debounce

  • 디바운싱(Debouncing)은 시간이 많이 걸리는 작업이 자주 실행되지 않도록 사용되는 프로그래밍 방법입니다.
  • 디바운싱은 함수가 실행되기 전에 일정 시간을 대기하도록 합니다. 즉, 함수가 호출되는 속도를 제한합니다.
  • 함수가 여러 번 호출되면, 일정 시간이 지난 후 마지막에 호출된 함수만 실행되고 이전의 호출된 함수는 무시됩니다.
  • Ex) 함수 호출 후 10초 동안 함수를 호출하지 않았다면, 10초가 지난 후 제일 마지막에 호출된 함수만 실행

Lodash의 Throttle 함수 사용

Lodash에는 지정된 시간 간격에 함수가 한 번만 실행되도록 제한하는 throttle 기능이 존재합니다.

다음은 Lodash의 throttle를 사용한 코드입니다.

import React, { useEffect, useRef, useState } from "react";
import { throttle } from "lodash";

export default function App() {
  const [value, setValue] = useState(0);
  const throttled = useRef(
    throttle((newValue) => console.log(newValue), 10000));
  
  useEffect(() => throttled.current(value), [value]);
  
  return <button onClick={() => setValue(value + 1)}>{value}</button>;
}

throttle는 실행하려는 함수를 지정된 시간 간격(밀리초)으로 호출합니다.

위 코드에서 밀리초를 10000으로 설정하였으므로 10초마다 한 번씩 실행됩니다.

throttle를 적용한 함수를 useRef Hook에 저장하여 throttled 함수를 throttled.current 값으로 설정합니다.

state가 변경되면, useEffect Callback에서 throttled 함수를 호출합니다.

버튼을 클릭하여 value의 값이 변경되면, 10초마다 함수가 실행되는 것을 console에서 확인할 수 있습니다.

Throttle 함수가 저장된 useCallback Hook 사용

위 코드에서 useRef를 useCallback Hook으로 교체할 수 있습니다.

import React, { useEffect, useCallback, useState } from "react";
import { throttle } from "lodash";

export default function App() {
  const [value, setValue] = useState(0);
  const throttled = useCallback(
    throttle((newValue) => console.log(newValue), 10000),
    []
  );

  useEffect(() => throttled(value), [value]);

  return <button onClick={() => setValue(value + 1)}>{value}</button>;
}

Debounce 함수

디바운싱 함수는 useCallback Hook를 사용하여 자체적으로 구현할 수 있습니다.
useCallback으로 감싸줘야 한다.

import React, { useCallback, useEffect, useState } from "react";

const useDebouncedEffect = (func, delay, deps) => {
  const callback = useCallback(func, deps);

  useEffect(() => {
    const timer = setTimeout(() => {
      callback();
    }, delay);

    return () => {
      clearTimeout(timer);
    };
  }, [callback, delay]);
};

export default function App() {
  const [value, setValue] = useState(0);

  useDebouncedEffect(() => console.log(value), 1000, [value]);

  return <button onClick={() => setValue(value + 1)}>{value}</button>;
}

프로젝트 예시

components > table > productionInformation

 const debounce = useCallback(debounceGenerator(400), [])

export const debounceGenerator = (ms) => {
  let id
  return (cb) => {
    if (id) {
      clearTimeout(id)
    }
    id = setTimeout(() => {
      cb()
      id = null
    }, ms)
  }
}

자체적으로 구현한 useDebounceEffect() 함수를 호출하여 useEffect Callback에 setTimeout() 함수를 호출합니다.

특정 시간 후 호출되어야 하는 함수는 useDebounceEffect() 함수에 첫 번째 인자로 전달합니다.

deps는 콜백의 의존성이며, 콜백의 의존성이 변경되었을 때에만 useCallback이 함수(func)를 변경합니다.

즉, useCallback Hook의 두 번째 인자인 deps의 값이 변경되면, 첫 번째 인자인 함수(func)를 재생성합니다.

setTimeout() 함수는 특정 시간이 지난 후 콜백을 실행합니다.

특정 시간이 지나지 않았는데, 함수가 다시 호출되는 경우 clearTimeout() 함수는 setTimeout()을 취소합니다.

debounce 키워드 검색

src > components > domain > TagSearhModal > TagSearchModal > TagSearchModal

useEffect(() => {
    if (!tags) {
      return
    }
    if (!keyword.length) {
      setFilteredTags(tags)
      return
    }
    debounce(() => {
      setFilteredTags(() => tags.filter((tag) => tag.includes(keyword))) // 키워드 검색
    })
  }, [tags, keyword])

* 참고 링크 1
* 참고 링크 2

0개의 댓글