@qazuor/react-hooks
Version:
A comprehensive collection of production-ready React hooks for modern web applications. Features type-safe implementations, extensive testing, and zero dependencies. Includes hooks for state management, browser APIs, user interactions, and development uti
123 lines (111 loc) • 3.87 kB
text/typescript
import { useCallback, useMemo, useState } from 'react';
interface QueueOperations<T> {
/** Add an item to the end of the queue */
enqueue: (item: T) => void;
/** Remove and return the first item from the queue */
dequeue: () => T | undefined;
/** Clear all items from the queue */
clear: () => void;
/** Get the first item without removing it */
peek: () => T | undefined;
/** Get the last item without removing it */
peekLast: () => T | undefined;
/** Check if the queue is empty */
isEmpty: boolean;
/** Get the current size of the queue */
size: number;
/** Get all items as an array */
toArray: () => T[];
/** Check if an item exists in the queue */
contains: (item: T) => boolean;
}
interface UseQueueOptions<T> {
/** Maximum size of the queue. Default is unlimited. */
maxSize?: number;
/** Callback when queue is full */
onFull?: () => void;
/** Callback when queue becomes empty */
onEmpty?: () => void;
/** Custom equality function for contains() */
equalityFn?: (a: T, b: T) => boolean;
}
/**
* useQueue
*
* @description A custom hook that manages a FIFO (first-in-first-out) queue.
* It provides methods to add items, remove items, reset the queue, and retrieve the first/last element.
*
* @param {T[]} initialValues - Initial items in the queue.
* @param {UseQueueOptions<T>} [options] - Optional configuration.
* @typeParam T - The type of items in the queue.
* @returns {QueueOperations<T>} - An object containing queue operations and state.
*
* @example
* ```ts
* const { enqueue, dequeue, size, peek, toArray } = useQueue<number>([1, 2]);
* enqueue(3);
* console.log(toArray()); // [1, 2, 3]
* const first = dequeue(); // first is 1, queue becomes [2, 3]
* console.log(peek()); // 2
* ```
*/
export function useQueue<T>(initialValues: T[] = [], options: UseQueueOptions<T> = {}): QueueOperations<T> {
const { maxSize, onFull, onEmpty, equalityFn = (a, b) => a === b } = options;
const [queue, setQueue] = useState<T[]>(initialValues);
const enqueue = useCallback(
(item: T) => {
setQueue((q) => {
if (maxSize && q.length >= maxSize) {
onFull?.();
return q;
}
return [...q, item];
});
},
[maxSize, onFull]
);
const dequeue = useCallback(() => {
// Get the element to return BEFORE scheduling the state update
if (queue.length === 0) {
return undefined;
}
const itemToDequeue = queue[0];
// Schedule the state update to remove the first element
setQueue((currentQueue) => {
if (currentQueue.length === 0) return currentQueue;
const newQueue = currentQueue.slice(1);
if (onEmpty && currentQueue.length > 0 && newQueue.length === 0) {
onEmpty();
}
return newQueue;
});
// Return the element we got BEFORE scheduling the state update
return itemToDequeue;
}, [queue, onEmpty]);
const clear = useCallback(() => {
if (onEmpty && queue.length > 0) {
onEmpty();
}
setQueue([]);
}, [onEmpty, queue]);
const peek = useCallback(() => queue[0], [queue]);
const peekLast = useCallback(() => queue[queue.length - 1], [queue]);
const contains = useCallback((item: T) => queue.some((i) => equalityFn(i, item)), [queue, equalityFn]);
const state = useMemo(
() => ({
isEmpty: queue.length === 0,
size: queue.length,
toArray: () => [...queue]
}),
[queue]
);
return {
enqueue,
dequeue,
clear,
peek,
peekLast,
contains,
...state
};
}