React Native Swiper ref element scrollTo does not work on first render

1.6k Views Asked by At

I am implementing an Introduction feature in my app. Where the screens show after splash screen. I used react-native-swiper component for guiding the user to step by step tutorial in my app.

Here is my Slider.tsx component code below.

type SliderProps = {
  // swiperEl: RefObject<Swiper>;
  // onIndexChanged: (index: number) => void;
  index: number;
};

const Slider = ({ index }: SliderProps) => {
  const swiperEl = useRef(null);
  useEffect(() => {
    swiperEl.current!.scrollTo(index);
  }, [index, swiperEl]);
  return (
    <View style={styles.sliderContainer}>
      <Swiper
        scrollEnabled={false}
        index={index}
        ref={swiperEl}
        style={styles.wrapper}
      >
        <View style={styles.slide1}>
          <View style={[styles.circle, { backgroundColor: '#FF7F50' }]} />
        </View>
        <View style={styles.slide2}>
          <View style={[styles.circle, { backgroundColor: '#FF6347' }]} />
        </View>
        <View style={styles.slide3}>
          <View style={[styles.circle, { backgroundColor: '#FF4500' }]} />
        </View>
      </Swiper>
    </View>
  );
};

and here is my WelcomeScreenContainer.tsx

const WelcomeScreen = () => {
  const [currentPage, setPage] = useState(0);
  const navigation = useNavigation();

  const handleNextClick = () => {
    if (currentPage === 2) {
      navigation.navigate('LoginScreen');
      return;
    }
    setPage((prevPage) => prevPage + 1);
  };

  const handleSkipPress = () => navigation.navigate('LoginScreen');

  console.log('Parent', currentPage);
  return (
    <View style={styles.parentContainer}>
      <View style={styles.headerContainer}>
        {/* <Text style={{ fontSize: 35 }}>WelcomeScreen</Text> */}
      </View>
      <Slider index={currentPage} />
      <View style={{ flex: 1 }} />
      <ButtonContainer
        onNextPress={handleNextClick}
        onSkipPress={handleSkipPress}
      />
    </View>
  );
};

Whenever I click the next button it should automatically slide the swiper to the next component or screen. However, on the first render when the user clicks the next button the swiperEl.current!.scrollTo(index); on the useEffect block of Slider.tsx does not work. But when the user clicks for the second time not it suddenly works.

I am a beginner in using React but I follow the documentation carefully on how to use the hooks of useRef and useEffect. Maybe I am missing something?

Appreciate it if someone could help. Thanks

1

There are 1 best solutions below

0
On

https://www.npmjs.com/package/react-native-swiper now supports scrollTo feature. I havent seen this in official documentation but maybe i wasnt careful enough, Here is what worked for me in year 2022

...
const milestoneData = [1, 2, 3, 4, 5] //your data
const mileStoneSwiperRef = useRef(null);

const scrollMileStoneTo = (index) => {
 mileStoneSwiperRef?.current?.scrollTo(index);
}



return (<View>
  <View style={{padding: 10, backgroundColor: BaseColor.mainColor2}}>
    <ScrollView showsHorizontalScrollIndicator={false} alwaysBounceHorizontal={true} horizontal={true} >
    {milestoneData?.map((item, index) => <>
              <Pressable onPress={() => scrollMileStoneTo(index)} style={{padding: 5, marginRight: 10, alignItems: 'center'}}>
                <Image source={Images.math}  style={[styles.contact, {width: 60, height: 60}]}/>
              </Pressable></>)}
    </ScrollView>
  </View>

  <Swiper
    ref={mileStoneSwiperRef}
    loop={false}
    centeredSlides={false}
    showsPagination={false}
    bounces={true}
    removeClippedSubviews={false}
  >

    {milestoneData?.map((item, index) => <View>


      <View style={styles.groupHeadingViews}>
        <Text fontResizeable bold style={styles.escrowGroupHeading}>{(`${tradeMethod} Name`).toUpperCase()}</Text>
        
        <View style={styles.subTitleAndWordCount}>
          <Text fontResizeable style={styles.escrowGroupSubHeading}>Briefly Name Your Country</Text>
          <Text fontResizeable style={styles.escrowGroupSubHeading}>{milestoneData?.[index]?.name?.length}/30</Text>
        </View>
      </View>
    </View>)}

  </Swiper>
</View>)
...

The trick to get the scrollTo() an index done is the following method

const scrollMileStoneTo = (index) => {
   mileStoneSwiperRef?.current?.scrollTo(index);
}