Skip to content

Instantly share code, notes, and snippets.

@rektdeckard
Last active May 8, 2022 03:17
Show Gist options
  • Save rektdeckard/37c79b11ff7969e1f333629be1d51df2 to your computer and use it in GitHub Desktop.
Save rektdeckard/37c79b11ff7969e1f333629be1d51df2 to your computer and use it in GitHub Desktop.
A React state toggle for arbitrary lists of values, where options are unchanging.
import { useState, useRef, useCallback } from "react";
/**
* Like `useCycle`, but more performant and guarantees a stable function reference
* for the lifetime of the hook. Only safe when the cycle options do not change.
*/
const useCycle = <T>(values: T[], initialState?: T): [T, () => void] => {
const valuesRef = useRef<T[]>(values);
const [index, setIndex] = useState<number>(() => {
const idx = initialState ? values.indexOf(initialState) : 0;
if (idx === -1) return 0;
return idx;
});
const cycle = useCallback(() => {
setIndex((idx) => (idx + 1) % valuesRef.current.length);
}, []);
return [valuesRef.current[index], cycle];
};
export default useCycle;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment