43 lines
1.4 KiB
TypeScript
43 lines
1.4 KiB
TypeScript
import { useCallback, useState } from 'react'
|
|
|
|
type QueueItem = { id: string }
|
|
|
|
type EffectQueueState<T extends QueueItem> = {
|
|
active?: T
|
|
pending: T[]
|
|
}
|
|
|
|
export function enqueueEffect<T extends QueueItem>(
|
|
state: EffectQueueState<T>,
|
|
effect: T,
|
|
capacity: number,
|
|
): EffectQueueState<T> {
|
|
if (state.active?.id === effect.id || state.pending.some(item => item.id === effect.id)) {
|
|
return state
|
|
}
|
|
if (!state.active) return { active: effect, pending: state.pending }
|
|
const boundedCapacity = Number.isFinite(capacity) ? Math.max(1, Math.floor(capacity)) : 1
|
|
if (state.pending.length >= boundedCapacity) return state
|
|
return { ...state, pending: [...state.pending, effect] }
|
|
}
|
|
|
|
export function completeEffect<T extends QueueItem>(
|
|
state: EffectQueueState<T>,
|
|
activeId: string,
|
|
): EffectQueueState<T> {
|
|
if (state.active?.id !== activeId) return state
|
|
const [active, ...pending] = state.pending
|
|
return { active, pending }
|
|
}
|
|
|
|
export function useEffectQueue<T extends QueueItem>() {
|
|
const [state, setState] = useState<EffectQueueState<T>>({ pending: [] })
|
|
const enqueue = useCallback((effect: T, capacity: number) => {
|
|
setState(current => enqueueEffect(current, effect, capacity))
|
|
}, [])
|
|
const complete = useCallback((activeId: string) => {
|
|
setState(current => completeEffect(current, activeId))
|
|
}, [])
|
|
return { active: state.active, pendingCount: state.pending.length, enqueue, complete }
|
|
}
|