Skip to content

Instantly share code, notes, and snippets.

@romellem
Last active November 9, 2021 15:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save romellem/4d3f6ace346b59c32b84f1b4af4214de to your computer and use it in GitHub Desktop.
Save romellem/4d3f6ace346b59c32b84f1b4af4214de to your computer and use it in GitHub Desktop.
React hook to allow for "wrapping" index setters
import { useCallback, useState } from 'react';
/**
* @typedef {Object} UseWrappedIndexResult
* @property {Number} index
* @property {Function} prev
* @property {Function} next
* @property {Function} setIndex
*/
/**
* @param {Number} maxIndex
* @param {Number} [initialIndex=0]
* @returns {UseWrappedIndexResult}
* @example `const { index, prev, next } = useWrappedIndex(images.length - 1);`
*/
function useWrappedIndex(maxIndex, initialIndex = 0) {
if (
typeof maxIndex !== "number" ||
maxIndex < 0 ||
Number.isNan(maxIndex)
) {
throw new Error("Invalid maxIndex passed");
}
if (
typeof initialIndex !== "number" ||
initialIndex < 0 ||
initialIndex > maxIndex ||
Number.isNan(initialIndex)
) {
initialIndex = 0;
}
const [index, setIndex] = useState(initialIndex);
const prev = useCallback(() => {
setIndex((currentIndex) => {
let newIndex = currentIndex - 1;
if (newIndex < 0) {
newIndex = maxIndex;
}
return newIndex;
});
}, [maxIndex]);
const next = useCallback(() => {
setIndex((currentIndex) => {
let newIndex = currentIndex + 1;
if (newIndex > maxIndex) {
newIndex = 0;
}
return newIndex;
});
}, [maxIndex]);
return {
index,
prev,
next,
setIndex,
// Allow for `const [index, prev, next, setIndex] = useWrappedIndex(...)`
*[Symbol.iterator]() {
yield index;
yield prev;
yield next;
yield setIndex;
},
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment