import { useMemo , useRef } from 'react' ; import useMountedState from './useMountedState' ; import useUpdate from './useUpdate' ; import useUpdateEffect from './useUpdateEffect' ; export interface UseStateListReturn < T > { state : T ; currentIndex : number ; setStateAt : ( newIndex : number ) => void ; setState : ( state : T ) => void ; next : ( ) => void ; prev : ( ) => void ; } export default function useStateList < T > ( stateSet = [ ] ) { const isMounted = useMountedState ( ) ; const update = useUpdate ( ) ; const index = useRef ( 0 ) ; useUpdateEffect ( ( ) => { if ( stateSet . length <= index . current ) { index . current = stateSet . length - 1 ; update ( ) ; } } , [ stateSet . length ] ) ; const actions = useMemo ( ( ) => ( { next : ( ) => actions . setStateAt ( index . current + 1 ) , prev : ( ) => actions . setStateAt ( index . current - 1 ) , setStateAt : ( newIndex ) => { if ( ! isMounted ( ) ) return ; if ( ! stateSet . length ) return ; if ( newIndex === index . current ) return ; index . current = newIndex >= 0 ? newIndex % stateSet . length : stateSet . length + ( newIndex % stateSet . length ) ; update ( ) ; } , setState : ( state ) => { if ( ! isMounted ( ) ) return ; const newIndex = stateSet . length ? stateSet . indexOf ( state ) : - 1 ; if ( newIndex === - 1 ) { throw new Error ( `State '${ state }' is not a valid state (does not exist in state list)` ) ; } index . current = newIndex ; update ( ) ; } , } ) , [ stateSet ] ) ; return { state : stateSet [ index . current ] , currentIndex : index . current , ... actions , } ; }