ScrolltoIndex is inconsistently returning to index 0 at the end in React Native

I’m having a strange behavior where the Slider I made sometimes returns to index 0 (first slide), but most times it returns to index 1. I made a Sandbox in case you need it, but I can’t figure out how to make expo work in sandbox.

HERE is the sandbox

Here’s the code for that view

import React, { useEffect, useRef, useState } from "react";
import { StyleSheet, SafeAreaView, Animated, FlatList, View, Text, Image, Dimensions, Pressable } from "react-native";

const data = [
  {
    id: 1,
    text: "Making Testing Easier",
    img: "https://e1.pxfuel.com/desktop-wallpaper/85/884/desktop-wallpaper-beautiful-judo-throws-judoka-thumbnail.jpg",
  },
  {
    id: 2,
    text: "Instructional Videos",
    img: "https://i.pinimg.com/originals/2b/84/c9/2b84c904ec3373b90f4fcad956233211.jpg",
  },
  {
    id: 3,
    text: "Newaza Fully Expanded",
    img: "https://i.pinimg.com/474x/d4/55/8c/d4558cf325344900b9eead6cb74dab20.jpg",
  },
];

const { width } = Dimensions.get("screen");

const CustomButton = ({ onPress, title, btnstyle, textstyle }) => {
  return (
    <Pressable style={btnstyle} onPress={onPress}>
      <Text style={textstyle}>{title}</Text>
    </Pressable>
  );
};

const SlideItem = ({ item }) => {
  return (
    <View style={styles.slideitemcontainer}>
      <View style={styles.overlay}>
        <Image source={item.img} resizeMode="cover" style={styles.image} />
      </View>
      <View style={styles.txtcontent}>
        <Text style={styles.title}>{item.text}</Text>
      </View>
      <View style={styles.btncontent}>
        <CustomButton
          title="Get Started"
          btnstyle={styles.btnPrimary}
          textstyle={styles.btnPrimaryText}
        />
        <CustomButton
          title="Login"
          btnstyle={styles.btnSecondary}
          textstyle={styles.btnSecondaryText}
        />
      </View>
    </View>
  );
};

const Pagination = ({ data, scrollX }) => {
  return (
    <View style={styles.paginationcontainer}>
      {data.map((_, idx) => {
        const inputRange = [(idx - 1) * width, idx * width, (idx + 1) * width];

        const dotWidth = scrollX.interpolate({
          inputRange,
          outputRange: [12, 30, 12],
          extrapolate: "clamp",
        });

        const backgroundColor = scrollX.interpolate({
          inputRange,
          outputRange: [
            "rgba(255, 255, 255, .3)",
            "rgba(204, 204, 204, .7)",
            "rgba(255, 255, 255, .3)",
          ],
          extrapolate: "clamp",
        });
        return (
          <Animated.View
            key={idx.toString()}
            style={[styles.dot, { width: dotWidth, backgroundColor }]}
          />
        );
      })}
    </View>
  );
};

const App = () => {
  const [index, setIndex] = useState(0);
  const scrollX = useRef(new Animated.Value(0)).current;
  const flatlistRef = useRef(null);

  const handleScroll = (event) => {
    Animated.event(
      [
        {
          nativeEvent: {
            contentOffset: {
              x: scrollX,
            },
          },
        },
      ],
      {
        useNativeDriver: false,
      },
    )(event);
  };

  const handleOnViewableItemsChanged = useRef(({ viewableItems }) => {
    setIndex(viewableItems[0].index);
  }).current;

  const viewabilityConfig = useRef({
    itemVisiblePercentThreshold: 50,
  }).current;

  useEffect(() => {
    flatlistRef?.current?.scrollToIndex({
      behavior: "smooth",
      animated: true,
      index: index,
    });
  }, [index]);

  useEffect(() => {
    const timer = setTimeout(() => {
      const nextIndex = index === data.length - 1 ? 0 : index + 1;
      setIndex(nextIndex);
    }, 2000);
    return () => clearTimeout(timer);
  }, [index]);

  const getItemLayout = (data, index) => ({
    length: width,
    offset: width * index,
    index,
  });

  return (
    <SafeAreaView style={styles.container}>
      <FlatList
        data={data}
        ref={flatlistRef}
        getItemLayout={getItemLayout}
        renderItem={({ item }) => <SlideItem item={item} />}
        horizontal
        pagingEnabled
        snapToAlignment="center"
        showsHorizontalScrollIndicator={false}
        onScroll={handleScroll}
        onViewableItemsChanged={handleOnViewableItemsChanged}
        viewabilityConfig={viewabilityConfig}
      />
      <Pagination data={data} scrollX={scrollX} index={index} />
    </SafeAreaView>
  );
};

export default App;

const styles = StyleSheet.create({
  overlay: {
    position: "absolute",
    width: "100%",
    height: "100%",
    flex: 1,
    left: 0,
    top: 0,
    opacity: 0.7,
  },
  slideitemcontainer: {
    width,
    height,
    alignItems: "center",
    backgroundColor: "black",
  },
  image: {
    flex: 1,
    width,
  },
  txtcontent: {
    position: "absolute",
    top: "25%",
    paddingHorizontal: "2%",
  },
  btncontent: {
    position: "absolute",
    bottom: "25%",
    width: "70%",
  },
  title: {
    fontSize: 45,
    fontWeight: "bold",
    color: "#fff",
  },
  btnPrimary: {
    alignItems: "center",
    justifyContent: "center",
    paddingVertical: 8,
    paddingHorizontal: 36,
    borderRadius: 8,
    elevation: 3,
    backgroundColor: "#0079D1",
    borderColor: "#0079D1",
    borderStyle: "solid",
    borderWidth: 2,
    marginBottom: 10,
  },
  btnPrimaryText: {
    fontSize: 13,
    fontWeight: "600",
    color: "white",
    textTransform: "uppercase",
  },
  btnSecondary: {
    alignItems: "center",
    justifyContent: "center",
    paddingVertical: 8,
    paddingHorizontal: 36,
    borderRadius: 8,
    elevation: 3,
    backgroundColor: "white",
    borderColor: "#0079D1",
    borderStyle: "solid",
    borderWidth: 2,
  },
  btnSecondaryText: {
    fontSize: 13,
    fontWeight: "600",
    color: "#0079D1",
    textTransform: "uppercase",
  },
  usjacontainer: {
    width,
    display: "flex",
    alignItems: "center",
    position: "absolute",
    bottom: "13%",
  },
  usja: {
    width: 40,
    height: 40,
    alignItems: "center",
    display: "flex",
    justifyContent: "center",
  },
  paginationcontainer: {
    position: "absolute",
    bottom: 35,
    flexDirection: "row",
    height: 64,
    width: "100%",
    justifyContent: "center",
    alignItems: "center",
  },
  dot: {
    height: 12,
    width: 12,
    borderRadius: 6,
    marginHorizontal: 3,
    backgroundColor: "rgba(255, 255, 255, .4)",
  },
  dotActive: {
    backgroundColor: theme.colors.secondary,
  },
});

More specifically, the useEffect is probably where I am messing up

useEffect(() => {
    const timer = setTimeout(() => {
        const nextIndex = index === data.length - 1 ? 0 : index + 1;
        setIndex(nextIndex);
    }, 2000);
    return () => clearTimeout(timer);
}, [index]);

SIDENOTE – Is there a way to make it so that the animation only moves forward, rather than a backwards slide to 0? Infinity scroll is always so much more pleasant.