UNPKG

@mirawision/reactive-hooks

Version:

A comprehensive collection of 50+ React hooks for state management, UI interactions, device APIs, async operations, drag & drop, audio/speech, and more. Full TypeScript support with SSR safety.

96 lines (95 loc) 3.34 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QueueCancelledError = void 0; exports.useAsyncQueue = useAsyncQueue; const react_1 = require("react"); class QueueCancelledError extends Error { constructor() { super('Queue was cancelled'); this.name = 'QueueCancelledError'; } } exports.QueueCancelledError = QueueCancelledError; /** * A hook that manages a queue of async tasks and executes them sequentially. * Tasks are executed in FIFO order, and each task starts only after the previous one completes. * If a task fails, the error is propagated to the caller but the queue continues processing. * * @returns Object containing: * - enqueue: Function to add a task to the queue * - size: Current number of pending tasks * - running: Whether the queue is currently processing tasks * - clear: Function to clear all pending tasks * * @example * const queue = useAsyncQueue(); * await queue.enqueue(() => api.saveItem(item)); * await queue.enqueue(() => api.updateStatus(status)); */ function useAsyncQueue() { const [size, setSize] = (0, react_1.useState)(0); const [running, setRunning] = (0, react_1.useState)(false); // Use refs to maintain queue state across renders const queueRef = (0, react_1.useRef)([]); const processingRef = (0, react_1.useRef)(false); const mountedRef = (0, react_1.useRef)(true); // Process queue items sequentially const processQueue = (0, react_1.useCallback)(async () => { if (processingRef.current || queueRef.current.length === 0) { return; } processingRef.current = true; setRunning(true); while (queueRef.current.length > 0 && mountedRef.current) { const { task, resolve, reject } = queueRef.current[0]; try { const result = await task(); if (mountedRef.current) { resolve(result); } else { reject(new QueueCancelledError()); } } catch (error) { reject(error); } if (mountedRef.current) { queueRef.current.shift(); setSize(queueRef.current.length); } } processingRef.current = false; setRunning(false); }, []); // Add task to queue const enqueue = (0, react_1.useCallback)((task) => { return new Promise((resolve, reject) => { queueRef.current.push({ task, resolve, reject }); setSize(queueRef.current.length); processQueue(); }); }, [processQueue]); // Clear all pending tasks const clear = (0, react_1.useCallback)(() => { const error = new QueueCancelledError(); queueRef.current.forEach(({ reject }) => reject(error)); queueRef.current = []; setSize(0); }, []); // Cleanup on unmount (0, react_1.useEffect)(() => { mountedRef.current = true; return () => { mountedRef.current = false; const error = new QueueCancelledError(); queueRef.current.forEach(({ reject }) => reject(error)); }; }, []); return { enqueue, size, running, clear, }; }