function useAsyncRateLimiter<TFn, TSelected>(
fn,
options,
selector): ReactAsyncRateLimiter<TFn, TSelected>
function useAsyncRateLimiter<TFn, TSelected>(
fn,
options,
selector): ReactAsyncRateLimiter<TFn, TSelected>
定义于: react-pacer/src/async-rate-limiter/useAsyncRateLimiter.ts:178
一个低级别的 React hook,用于创建一个 AsyncRateLimiter 实例,以限制异步函数在一个时间窗口内可以执行的次数。
此 hook 设计灵活且独立于状态管理 - 它仅返回一个速率限制器实例,您可以将其集成到任何状态管理解决方案中(useState、Redux、Zustand、Jotai 等)。
速率限制允许异步函数在一个时间窗口内执行指定次数,然后阻止后续调用,直到窗口期过去。这对于遵守 API 速率限制、管理资源约束或控制异步操作的爆发非常有用。
与非异步的 RateLimiter 不同,此异步版本支持从速率受限函数返回。这使其非常适合 API 调用和其他异步操作,您希望在其中获取 maybeExecute 调用的结果,而不是在速率受限函数内部将结果设置到状态变量中。
速率限制器支持两种类型的窗口
错误处理
该 hook 使用 TanStack Store 进行响应式状态管理。 selector 参数允许您指定哪些状态更改将触发重新渲染,通过防止不相关的状态更改发生不必要的重新渲染来优化性能。
默认情况下,将没有响应式状态订阅,您必须通过提供 selector 函数来选择加入状态跟踪。这可以防止不必要的重新渲染,并让您完全控制组件何时更新。只有在您提供 selector 时,组件才会在选定的状态值发生更改时重新渲染。
可用的状态属性
• TFn extends AnyAsyncFunction
• TSelected = {}
TFn
AsyncRateLimiterOptions<TFn>
(state) => TSelected
ReactAsyncRateLimiter<TFn, TSelected>
// Default behavior - no reactive state subscriptions
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data; // Return value is preserved
},
{ limit: 5, window: 1000 } // 5 calls per second
);
// Opt-in to re-render when execution state changes (optimized for loading indicators)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{ limit: 5, window: 1000 },
(state) => ({ isExecuting: state.isExecuting })
);
// Opt-in to re-render when results are available (optimized for data display)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{ limit: 5, window: 1000 },
(state) => ({
lastResult: state.lastResult,
successCount: state.successCount
})
);
// Opt-in to re-render when error/rejection state changes (optimized for error handling)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{
limit: 5,
window: 1000,
onError: (error) => console.error('API call failed:', error),
onReject: (rateLimiter) => console.log('Rate limit exceeded')
},
(state) => ({
errorCount: state.errorCount,
rejectionCount: state.rejectionCount
})
);
// Opt-in to re-render when execution metrics change (optimized for stats display)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{ limit: 5, window: 1000 },
(state) => ({
successCount: state.successCount,
errorCount: state.errorCount,
settleCount: state.settleCount,
rejectionCount: state.rejectionCount
})
);
// Opt-in to re-render when execution times change (optimized for window calculations)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{ limit: 5, window: 1000 },
(state) => ({ executionTimes: state.executionTimes })
);
// With state management and return value
const [data, setData] = useState(null);
const { maybeExecute, state } = useAsyncRateLimiter(
async (query) => {
const result = await searchAPI(query);
setData(result);
return result; // Return value can be used by the caller
},
{
limit: 10,
window: 60000, // 10 calls per minute
onReject: (rateLimiter) => {
console.log(`Rate limit exceeded. Try again in ${rateLimiter.getMsUntilNextWindow()}ms`);
},
onError: (error) => {
console.error('API call failed:', error);
}
}
);
// Access the selected state (will be empty object {} unless selector provided)
const { isExecuting, lastResult, rejectionCount } = state;
// Default behavior - no reactive state subscriptions
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data; // Return value is preserved
},
{ limit: 5, window: 1000 } // 5 calls per second
);
// Opt-in to re-render when execution state changes (optimized for loading indicators)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{ limit: 5, window: 1000 },
(state) => ({ isExecuting: state.isExecuting })
);
// Opt-in to re-render when results are available (optimized for data display)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{ limit: 5, window: 1000 },
(state) => ({
lastResult: state.lastResult,
successCount: state.successCount
})
);
// Opt-in to re-render when error/rejection state changes (optimized for error handling)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{
limit: 5,
window: 1000,
onError: (error) => console.error('API call failed:', error),
onReject: (rateLimiter) => console.log('Rate limit exceeded')
},
(state) => ({
errorCount: state.errorCount,
rejectionCount: state.rejectionCount
})
);
// Opt-in to re-render when execution metrics change (optimized for stats display)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{ limit: 5, window: 1000 },
(state) => ({
successCount: state.successCount,
errorCount: state.errorCount,
settleCount: state.settleCount,
rejectionCount: state.rejectionCount
})
);
// Opt-in to re-render when execution times change (optimized for window calculations)
const asyncRateLimiter = useAsyncRateLimiter(
async (id: string) => {
const data = await api.fetchData(id);
return data;
},
{ limit: 5, window: 1000 },
(state) => ({ executionTimes: state.executionTimes })
);
// With state management and return value
const [data, setData] = useState(null);
const { maybeExecute, state } = useAsyncRateLimiter(
async (query) => {
const result = await searchAPI(query);
setData(result);
return result; // Return value can be used by the caller
},
{
limit: 10,
window: 60000, // 10 calls per minute
onReject: (rateLimiter) => {
console.log(`Rate limit exceeded. Try again in ${rateLimiter.getMsUntilNextWindow()}ms`);
},
onError: (error) => {
console.error('API call failed:', error);
}
}
);
// Access the selected state (will be empty object {} unless selector provided)
const { isExecuting, lastResult, rejectionCount } = state;
您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。