본문으로 건너뛰기

함수: useRateLimiter()

function useRateLimiter<TFn, TSelected>(
fn,
options,
selector): ReactRateLimiter<TFn, TSelected>;

정의 위치: react-pacer/src/rate-limiter/useRateLimiter.ts:190

함수 실행에 요청률 제한을 적용하는 RateLimiter 인스턴스를 생성하는 하위 수준 React 훅입니다.

유연하고 상태 관리 방식에 구애받지 않도록 설계되었습니다. 요청률 제한기 인스턴스만 반환하므로 어떤 상태 관리 솔루션(useState, Redux, Zustand, Jotai 등)과도 통합할 수 있습니다.

요청률 제한은 시간 윈도우 안에서 최대 횟수에 도달할 때까지 실행을 허용한 뒤 윈도우가 초기화될 때까지 이후 모든 호출을 차단하는 단순한 "하드 제한" 방식입니다. 스로틀이나 디바운스와 달리 실행 간격을 조정하거나 실행을 지능적으로 합치지 않습니다.

요청률 제한기는 두 가지 윈도우 유형을 지원합니다.

  • 'fixed': 윈도우 기간이 지나면 초기화되는 엄격한 윈도우입니다. 윈도우 안의 모든 실행이 한도에 포함되며 기간이 지나면 윈도우가 완전히 초기화됩니다.
  • 'sliding': 이전 실행이 만료됨에 따라 실행을 허용하는 롤링 윈도우입니다. 시간에 걸쳐 더 일정한 실행률을 제공합니다.

더 부드러운 실행 패턴이 필요하다면:

  • 실행 간격을 일정하게 유지하려면 스로틀을 사용합니다(예: UI 업데이트).
  • 빠르게 연속되는 이벤트를 합치려면 디바운스를 사용합니다(예: 검색 입력).
  • 하드 제한을 적용해야 할 때만 요청률 제한을 사용합니다(예: API 요청률 제한).

상태 관리와 셀렉터

훅은 반응형 상태 관리에 TanStack Store를 사용합니다. 다음 두 가지 방식으로 상태 변경을 구독할 수 있습니다.

1. rateLimiter.Subscribe HOC 사용(컴포넌트 트리 구독에 권장)

Subscribe HOC를 사용하면 컴포넌트 트리 깊은 곳의 상태 변경을 구독할 때 훅에 셀렉터를 전달할 필요가 없습니다. 자식 컴포넌트에서 상태를 구독하려는 경우에 적합합니다.

2. selector 매개변수 사용(훅 수준 구독)

selector 매개변수를 사용하면 어떤 상태 변경이 재렌더링을 트리거할지 지정할 수 있으며 관련 없는 상태가 변경될 때 불필요한 재렌더링을 방지하여 훅 수준의 성능을 최적화합니다.

기본적으로 반응형 상태 구독은 없습니다. 상태 추적을 명시적으로 활성화하려면 셀렉터 함수를 제공하거나 Subscribe HOC를 사용해야 합니다. 이렇게 하면 불필요한 재렌더링을 방지하고 컴포넌트가 업데이트되는 시점을 완전히 제어할 수 있습니다.

사용 가능한 상태 속성:

  • executionCount: 완료된 함수 실행 횟수
  • executionTimes: 요청률 제한 계산을 위해 실행이 발생한 시점의 타임스탬프 배열
  • rejectionCount: 요청률 제한으로 거부된 함수 실행 횟수

훅은 다음 요소를 담은 객체를 반환합니다.

  • maybeExecute: 구성된 제한을 준수하는 요청률 제한 함수
  • getExecutionCount: 성공한 실행 횟수를 반환합니다.
  • getRejectionCount: 요청률 제한으로 거부된 실행 횟수를 반환합니다.
  • getRemainingInWindow: 현재 윈도우에서 추가로 허용되는 실행 횟수를 반환합니다.
  • reset: 실행 횟수와 윈도우 타이밍을 초기화합니다.

타입 매개변수

TFn

TFn extends AnyFunction

TSelected

TSelected = { }

매개변수

fn

TFn

options

ReactRateLimiterOptions&lt;TFn, TSelected>

selector

(state) => TSelected

반환값

ReactRateLimiter&lt;TFn, TSelected>

예시

// Default behavior - no reactive state subscriptions
const rateLimiter = useRateLimiter(apiCall, {
limit: 5,
window: 60000,
windowType: 'sliding',
});

// Subscribe to state changes deep in component tree using Subscribe HOC
<rateLimiter.Subscribe selector={(state) => ({ rejectionCount: state.rejectionCount })}>
{({ rejectionCount }) => (
<div>Rejected: {rejectionCount} requests</div>
)}
</rateLimiter.Subscribe>

// Opt-in to re-render when execution count changes at hook level (optimized for tracking successful executions)
const rateLimiter = useRateLimiter(
apiCall,
{
limit: 5,
window: 60000,
windowType: 'sliding',
},
(state) => ({ executionCount: state.executionCount })
);

// Opt-in to re-render when rejection count changes (optimized for tracking rate limit violations)
const rateLimiter = useRateLimiter(
apiCall,
{
limit: 5,
window: 60000,
windowType: 'sliding',
},
(state) => ({ rejectionCount: state.rejectionCount })
);

// Opt-in to re-render when execution times change (optimized for window calculations)
const rateLimiter = useRateLimiter(
apiCall,
{
limit: 5,
window: 60000,
windowType: 'sliding',
},
(state) => ({ executionTimes: state.executionTimes })
);

// Multiple state properties - re-render when any of these change
const rateLimiter = useRateLimiter(
apiCall,
{
limit: 5,
window: 60000,
windowType: 'sliding',
},
(state) => ({
executionCount: state.executionCount,
rejectionCount: state.rejectionCount
})
);

// Monitor rate limit status
const handleClick = () => {
const remaining = rateLimiter.getRemainingInWindow();
if (remaining > 0) {
rateLimiter.maybeExecute(data);
} else {
showRateLimitWarning();
}
};

// Access the selected state (will be empty object {} unless selector provided)
const { executionCount, rejectionCount } = rateLimiter.state;