디바운스 분리 과정

robin Han·2025년 4월 6일
2

상황설명

현재 곳곳에서 사용되고있는 입력값 input을 바로바로 zustand 상태 변환을 통해서 사용하고있다. 하지만 이렇게 되면 너무 많은 리랜더링이 일어나고 해당 리랜더링으로 인해서 다른 컴포넌트들도 같이 랜더링이 되는 사이드이팩트도 발생하기 때문에 최소한 불필요한 랜더링은 줄이는 방법이 가장 좋다고 생각해서 리팩토링 결정을 했다.

생각한 여러가지 방법들

  • 디바운싱
    우선적을 디바운싱이 가장 먼저 떠올랐다, 검색어 기능 같이 입력값에서 많이 사용하는 방법으로 마지막 입력을 기점으로 딜레이를 만들어 해당 상태가 변하게 하는 방법이다, 입력할때 마다 랜더링이 되는것이 아니라 해당 딜레이가 끝난후에 받는 값으로 상태가 바뀌기 떄문에 최소한의 랜더링으로 구현이 가능
  • 쓰로틀
    디바운싱과 비슷하지만 쓰로틀은 일정시간마다 한번 실해을해주는 방법인데, 사용자한테 입력을받고 다음 단계로 넘어가기전에 마지막에 한번만 상태변화를 감지하면 되는 상황이라 맞지않다.
  • useRef
    리랜더링이 되지않고 해당 컴포넌트 인풋의 입력값은 계속 바뀔수있는 방법이 있다 하지만 해당 방법은 리랜더링을 줄일수있지만, 우리 상황에서 아에 리랜더링이 되지않게 하는건 미리보기에서도 랜더링이 되지않은값을 표시 할수없어서 useRef로만은 부족했다

그러면 두가지 를 합치면 ??
우선 디바운싱방법이 가장 적합하고 useRef를 사용해서 해당 리렌더링을 최소화 시키면 가장 좋은 방법이 될수있지 않을까 라는 생각을 하게되었다

import { useRef, useEffect } from 'react';

export function useDebouncedCallback<T extends (...args: any[]) => {
  const callbackRef = useRef(callback);

  const debounced = (...args: Parameters<T>) => {
    argsRef.current = args;
    if (timeoutRef.current) clearTimeout(timeoutRef.current);
    timeoutRef.current = setTimeout(() => {
      if (argsRef.current) callbackRef.current(...argsRef.current);
    }, delay);
  };

  const flush = () => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
      if (argsRef.current) {
        callbackRef.current(...argsRef.current);
      }
    }
  };

}

만약 디바운싱 시간차에 다른 이벤트로 인해서 값이 제대로 전달되지않을때 flush 함수는 해당 입력이 디바운싱시간을 거치지않고 넘어갈때 사용한다 남아있는 값들을 바꾸고 cleartimeout 진행시킨다

2개의 댓글

comment-user-thumbnail
2025년 4월 6일

설명이 멋있고 사장님이 자세하네요

답글 달기
comment-user-thumbnail
2025년 4월 6일

우와 글 맛집 댓글 맛집이네요

답글 달기