I am making an infinite image carousel using hooks and javascript in react native.
I am almost done with the code and also the carousel works absolutely fine but the active dots below the carousel runs faster than the images. I have tried a couple of things but unfortunately it didn't worked out.
Thanks in advance.
import React, {
useEffect,
useState,
useRef,
useCallback,
createRef,
} from 'react';
import {
StyleSheet,
View,
Dimensions,
FlatList,
LayoutAnimation,
UIManager,
Text,
} from 'react-native';
import {ActivityIndicator} from 'react-native';
import {Image} from 'react-native-elements';
const HomeCarousel = ({data}) => {
const [dimension, setDimension] = useState(Dimensions.get('window'));
const [index, setIndex] = useState(0);
const [dataState, setDataState] = useState(data);
slider = createRef();
let intervalId = null;
const onChange = () => {
setDimension(Dimensions.get('window'));
};
useEffect(() => {
Dimensions.addEventListener('change', onChange);
return () => {
Dimensions.removeEventListener('change', onChange);
};
});
useEffect(() => {
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}, []);
viewabilityConfig = {
viewAreaCoveragePercentThreshold: 50,
};
const onViewableItemsChanged = ({viewableItems, changed}) => {
if (viewableItems.length > 0) {
let currentIndex = viewableItems[0].index;
if (currentIndex % data.length === data.length - 1) {
setIndex(currentIndex),
setDataState(dataState => [...dataState, ...data]);
} else {
console.log(currentIndex, 'else');
setIndex(currentIndex);
}
}
};
const onSlideChange = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeIn);
const newIndex = index + 1;
setIndex(newIndex);
slider?.current?.scrollToIndex({
index: index,
animated: true,
});
};
const startInterval = useCallback(() => {
intervalId = setInterval(onSlideChange, 3000);
}, [onSlideChange]);
useEffect(() => {
startInterval();
return () => {
clearInterval(intervalId);
};
}, [onSlideChange]);
const viewabilityConfigCallbackPairs = useRef([
{viewabilityConfig, onViewableItemsChanged},
]);
const renderIndicator = ()=>{
const indicators = [];
data.map((val,key)=>(
indicators.push(
<Text
key={key}
style={
key === index % data.length ? {color: 'lightblue',fontSize:10,marginBottom: 8,marginHorizontal:1} :
{color: '#888',fontSize:10,marginBottom: 8,marginHorizontal:1}
}>
⬤
</Text>
)
));
return indicators;
}
return (
<View style={{width: dimension.width,height: 280, backgroundColor: '#fff'}}>
<FlatList
ref={slider}
horizontal
pagingEnabled
snapToInterval={dimension?.width}
decelerationRate="fast"
bounces={false}
showsHorizontalScrollIndicator={false}
data={dataState}
renderItem={({item, index}) => (
<>
<View>
<Image
source={{uri: `${item.url}`}}
style={{
width: dimension?.width,
height: 250,
resizeMode: 'cover',
}}
PlaceholderContent={<ActivityIndicator />}
/>
</View>
</>
)}
viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs.current}
getItemLayout={(data, index) => ({
length: dimension?.width,
offset: dimension?.width * index,
index,
})}
windowSize={1}
initialNumToRender={1}
maxToRenderPerBatch={1}
removeClippedSubviews={true}
/>
<View
style={{
flexDirection: 'row',
position: 'absolute',
bottom: 0,
alignSelf: 'center',
}}>
{renderIndicator()}
</View>
</View>
);
};
const styles = StyleSheet.create({});
export default HomeCarousel;
The data that is passed as the props to this component is
export const carouselImages = [
{url: 'https://i.ibb.co/FDwNR9d/img1.jpg'},
{url: 'https://i.ibb.co/7G5qqGY/1.jpg'},
{url: 'https://i.ibb.co/Jx7xqf4/pexels-august-de-richelieu-4427816.jpg'},
{url: 'https://i.ibb.co/GV08J9f/pexels-pixabay-267202.jpg'},
{url: 'https://i.ibb.co/sK92ZhC/pexels-karolina-grabowska-4210860.jpg'},
];
Ooooooh, I fixed it myself Here is the perfectly working code full code. 😄
import React, {
useEffect,
useState,
useRef,
useCallback,
createRef,
} from 'react';
import {
StyleSheet,
View,
Dimensions,
FlatList,
LayoutAnimation,
UIManager,
Text,
} from 'react-native';
import {ActivityIndicator} from 'react-native';
import {Image} from 'react-native-elements';
const HomeCarousel = ({data}) => {
const [dimension, setDimension] = useState(Dimensions.get('window'));
const [index, setIndex] = useState(0);
const [dataState, setDataState] = useState(data);
const [indicatorIndex, setindicatorIndex] = useState();
slider = createRef();
let intervalId = null;
const onChange = () => {
setDimension(Dimensions.get('window'));
};
useEffect(() => {
Dimensions.addEventListener('change', onChange);
return () => {
Dimensions.removeEventListener('change', onChange);
};
});
useEffect(() => {
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}, []);
viewabilityConfig = {
viewAreaCoveragePercentThreshold: 50,
};
const onViewableItemsChanged = ({viewableItems, changed}) => {
if (viewableItems.length > 0) {
let currentIndex = viewableItems[0].index;
if (currentIndex % data.length === data.length - 1) {
setIndex(currentIndex), setindicatorIndex(currentIndex);
setDataState(dataState => [...dataState, ...data]);
} else {
console.log(currentIndex, 'else');
setIndex(currentIndex);
setindicatorIndex(currentIndex);
}
}
};
const onSlideChange = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeIn);
const newIndex = index + 1;
setIndex(newIndex);
slider?.current?.scrollToIndex({
index: index,
animated: true,
});
};
const startInterval = useCallback(() => {
intervalId = setInterval(onSlideChange, 3000);
}, [onSlideChange]);
useEffect(() => {
startInterval();
return () => {
clearInterval(intervalId);
};
}, [onSlideChange]);
const viewabilityConfigCallbackPairs = useRef([
{viewabilityConfig, onViewableItemsChanged},
]);
const renderIndicator = () => {
const indicators = [];
data.map((val, key) =>
indicators.push(
<Text
key={key}
style={
key === indicatorIndex % data.length
? {
color: 'lightblue',
fontSize: 10,
marginBottom: 8,
marginHorizontal: 1,
}
: {
color: '#888',
fontSize: 10,
marginBottom: 8,
marginHorizontal: 1,
}
}>
⬤
</Text>,
),
);
return indicators;
};
return (
<View
style={{width: dimension.width, height: 280, backgroundColor: '#fff'}}>
<FlatList
ref={slider}
horizontal
pagingEnabled
snapToInterval={dimension?.width}
decelerationRate="fast"
bounces={false}
showsHorizontalScrollIndicator={false}
data={dataState}
renderItem={({item, index}) => (
<>
<View>
<Image
source={{uri: `${item.url}`}}
style={{
width: dimension?.width,
height: 250,
resizeMode: 'cover',
}}
PlaceholderContent={<ActivityIndicator />}
/>
</View>
</>
)}
viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs.current}
getItemLayout={(data, index) => ({
length: dimension?.width,
offset: dimension?.width * index,
index,
})}
windowSize={1}
initialNumToRender={1}
maxToRenderPerBatch={1}
removeClippedSubviews={true}
/>
<View
style={{
flexDirection: 'row',
position: 'absolute',
bottom: 0,
alignSelf: 'center',
}}>
{renderIndicator()}
</View>
</View>
);
};
const styles = StyleSheet.create({});
export default HomeCarousel;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With