@supunlakmal/hooks
Version:
A collection of reusable React hooks
41 lines • 1.88 kB
JavaScript
import { useState, useCallback } from 'react';
/**
* @name useCycle
* @description - Hook that cycles through a predefined list of values.
*
* @template T The type of the values in the list.
* @param {T[]} items An array of items to cycle through.
* @param {number} [initialIndex=0] The index of the item to start with.
* @returns {[T, { next: () => void; prev: () => void; goTo: (index: number) => void; }]} A tuple containing the current item and an object with functions to cycle (`next`, `prev`) or jump (`goTo`) to a specific item.
* @throws If the items array is empty.
* @throws If the initialIndex is out of bounds.
*
* @example
* const [currentTheme, { next: cycleTheme, prev: previousTheme }] = useCycle(['light', 'dark']);
* const [currentValue, actions] = useCycle([10, 20, 30], 1);
*/
export const useCycle = (items, initialIndex = 0) => {
if (items.length === 0) {
throw new Error('useCycle requires a non-empty array of items.');
}
if (initialIndex < 0 || initialIndex >= items.length) {
throw new Error(`useCycle initialIndex (${initialIndex}) is out of bounds (0-${items.length - 1}).`);
}
const [index, setIndex] = useState(initialIndex);
const next = useCallback(() => {
setIndex((prevIndex) => (prevIndex + 1) % items.length);
}, [items.length]);
const prev = useCallback(() => {
setIndex((prevIndex) => (prevIndex - 1 + items.length) % items.length);
}, [items.length]);
const goTo = useCallback((targetIndex) => {
if (targetIndex >= 0 && targetIndex < items.length) {
setIndex(targetIndex);
}
else {
console.warn(`useCycle goTo: index (${targetIndex}) is out of bounds (0-${items.length - 1}).`);
}
}, [items.length]);
return [items[index], { next, prev, goTo }];
};
//# sourceMappingURL=useCycle.js.map