useStateList<T> function

UseStateList<T> useStateList<T>([
  1. List<T> stateSet = const []
])

Provides handles for circular iteration over states list. Supports forward and backward iterations and arbitrary position set.

Implementation

UseStateList<T> useStateList<T>([List<T> stateSet = const []]) {
  final isMounted = useIsMounted();
  final update = useUpdate();
  final index = useRef(0);

  // If new state list is shorter that before - switch to the last element
  // ignore: body_might_complete_normally_nullable
  useUpdateEffect(() {
    if (stateSet.length <= index.value) {
      index.value = stateSet.length - 1;
      update();
    }
  }, [stateSet.length]);

  final stateList = useCallback<List<T> Function()>(() => stateSet, const []);

  final currentIndex = useCallback<int Function()>(() => index.value, const []);

  final setStateAt = useCallback<void Function(int newIndex)>((int newIndex) {
    // do nothing on unmounted component
    if (!isMounted()) return;

    // do nothing on empty states list
    if (stateSet.isEmpty) return;

    // in case new index is equal current - do nothing
    if (newIndex == index.value) return;

    // it gives the ability to travel through the left and right borders.
    // 4ex: if list contains 5 elements, attempt to set index 9 will bring use to 5th element
    // in case of negative index it will set to the 0th.
    index.value = newIndex >= 0 ? newIndex % stateSet.length : 0;
    update();
  }, const []);

  final setState = useCallback<void Function(T state)>((T state) {
    // do nothing on unmounted component
    if (!isMounted()) return;

    final newIndex = stateSet.isNotEmpty ? stateSet.indexOf(state) : -1;

    if (newIndex == -1) {
      throw ArgumentError(
          "State $state is not a valid state (does not exist in state list)");
    }

    index.value = newIndex;
    update();
  }, const []);

  final next = useCallback<VoidCallback>(() {
    setStateAt(index.value + 1);
  }, const []);

  final prev = useCallback<VoidCallback>(() {
    setStateAt(index.value - 1);
  }, const []);

  final state = useRef(UseStateList<T>(
    stateList,
    currentIndex,
    setStateAt,
    setState,
    next,
    prev,
  ));
  return state.value;
}