[英]how can I make a custom carousel or image slide in react native without using any npm packages
I am making a custom image carousel or an image slider in react native without using any packages, the issue is that the dot indicators on the bottom are changing fine after 3 second intervals but the image doesn't slides automatically.我在不使用任何包的情况下在本机反应中制作自定义图像轮播或图像滑块,问题是底部的点指示器在 3 秒间隔后变化良好,但图像不会自动滑动。 There is some minor issue which I am unable to find.
有一些我找不到的小问题。 If you can help in getting this fixed without changing much of the code it would be really nice.
如果您可以在不更改大部分代码的情况下帮助解决此问题,那就太好了。 thanks in advance.
提前致谢。
Here is the full component code.这是完整的组件代码。
import React, {useEffect, useState, useRef} from 'react';
import {StyleSheet, ScrollView, View, Dimensions, Text} from 'react-native';
import {ActivityIndicator} from 'react-native';
import {Image} from 'react-native-elements';
const HomeCarousel = () => {
const [dimension, setDimension] = useState(Dimensions.get('window'));
const [selectedIndex, setSelectedIndex] = useState(0);
const scrollRef = useRef();
const onChange = () => {
setDimension(Dimensions.get('window'));
};
useEffect(() => {
Dimensions.addEventListener('change', onChange);
return () => {
Dimensions.removeEventListener('change', onChange);
};
});
useEffect(() => {
setInterval(() => {
setSelectedIndex(prevSelectedIndex =>
prevSelectedIndex === carouselImages.length - 1
? 0
: prevSelectedIndex + 1,
);
() => {
scrollRef.current.scrollTo({
animated: true,
y: 0,
x: dimension.width * selectedIndex,
});
};
}, 3000);
}, []);
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'},
];
const setIndex = event => {
let viewSize = event.nativeEvent.layoutMeasurement.width;
let contentOffset = event.nativeEvent.contentOffset.x;
let carouselIndex = Math.floor(contentOffset / viewSize);
setSelectedIndex(carouselIndex);
};
return (
<View style={{width: dimension.width}}>
<ScrollView
horizontal
ref={scrollRef}
onMomentumScrollEnd={setIndex}
showsHorizontalScrollIndicator={false}
pagingEnabled>
{carouselImages.map((value, key) => (
<Image
source={{uri: `${value.url}`}}
style={{width: dimension?.width, height: 250, resizeMode: 'cover'}}
PlaceholderContent={<ActivityIndicator />}
/>
))}
</ScrollView>
<View
style={{
flexDirection: 'row',
position: 'absolute',
bottom: 0,
alignSelf: 'center',
}}>
{carouselImages.map((val, key) => (
<Text
key={key}
style={key === selectedIndex ? {color: 'white'} : {color: '#888'}}>
⬤
</Text>
))}
</View>
</View>
);
};
const styles = StyleSheet.create({});
export default HomeCarousel;
Your images aren't being update because of 2 things:由于两件事,您的图像没有更新:
// You're just defining the function here and not actually calling it
() => {
scrollRef.current.scrollTo({
animated: true,
y: 0,
x: dimension.width * selectedIndex,
});
};
useEffect
doesn't have any dependencies, which means its callback won't be changed, and therefore the selectedIndex
inside of it will always be 0:useEffect
没有任何依赖关系,这意味着它的回调不会改变,因此其中的selectedIndex
将始终为 0:useEffect(() => {
setInterval(() => {
setSelectedIndex(prevSelectedIndex =>
prevSelectedIndex === carouselImages.length - 1
? 0
: prevSelectedIndex + 1,
);
() => {
scrollRef.current.scrollTo({
animated: true,
y: 0,
// Since there are no dependencies, this callback won't ever be changed and selectedIndex will always be 0
x: dimension.width * selectedIndex,
});
};
}, 3000);
// You have no dependencies here
}, []);
My suggestions for improvements/fixes would be:我对改进/修复的建议是:
useEffect
callback and apply a useCallback
hook with selectedIndex
dependency.useEffect
回调中更新幻灯片并应用带有selectedIndex
依赖项的useCallback
挂钩。 You should also calculate the value of the new index outside of the setSelectedIndex
hook, because setState/useState
doesn't update immediately :setSelectedIndex
挂钩之外计算新索引的值,因为setState/useState
不会立即更新:// You should also use an intervalId so that you can clear the interval/reset when needed
let intervalId = null;
const HomeCarousel = () => {
// ... rest of the HomeCarousel component
const onSlideChange = useCallback(() => {
// Calculate newIndex here and use it to update your state and to scroll to the new slide
const newIndex = selectedIndex === carouselImages.length - 1 ? 0 : selectedIndex + 1;
setSelectedIndex(newIndex);
scrollRef?.current?.scrollTo({
animated: true,
y: 0,
x: dimension.width * newIndex,
});
}, [selectedIndex]);
const startInterval = useCallback(() => {
intervalId = setInterval(onSlideChange, 3000);
}, [onSlideChange]);
useEffect(() => {
startInterval();
return () => {
// Clear the interval when component unmounts, otherwise you could have memory leaks
clearInterval(intervalId);
};
}, [onSlideChange]);
// ... rest of the HomeCarousel component
};
const onTouchStart = () => {
// As soon as the user touches the slide, stop the automatic sliding
clearInterval(intervalId);
};
const onTouchEnd = () => {
// As soon as the user stops touching the slide, releases it, start the automatic sliding again
startInterval();
};
return (
<ScrollView
// ... Other scrollview props
onTouchStart={onTouchStart}
onTouchEnd={onTouchEnd}>
{/* ... Rest of the component */}
const carouselImages = [ carousel1, carousel2, carousel3, carousel4, carousel5 ]; const Carousel = () => { const [current, setCurrent] = useState(0); useEffect(() => { const next = (current + 1) % carouselImages.length; const id = setTimeout(() => setCurrent(next), 3000); return () => clearTimeout(id); }, [current]); return ( <div className="banner"> <div className="slider"> <img src={carouselImages[current]} alt="carousel" /> </div> <div className="overlay"></div> </div> );
Here is the full working code.这是完整的工作代码。
import React, {useEffect, useState, useRef, useCallback} from 'react';
import {StyleSheet, ScrollView, View, Dimensions, Text} from 'react-native';
import {ActivityIndicator} from 'react-native';
import {Image} from 'react-native-elements';
const HomeCarousel = () => {
const [dimension, setDimension] = useState(Dimensions.get('window'));
const [selectedIndex, setSelectedIndex] = useState(0);
const scrollRef = useRef();
let intervalId = null;
const onChange = () => {
setDimension(Dimensions.get('window'));
};
useEffect(() => {
Dimensions.addEventListener('change', onChange);
return () => {
Dimensions.removeEventListener('change', onChange);
};
});
const onSlideChange = useCallback(() => {
// Calculate newIndex here and use it to update your state and to scroll to the new slide
const newIndex =
selectedIndex === carouselImages.length - 1 ? 0 : selectedIndex + 1;
setSelectedIndex(newIndex);
scrollRef?.current?.scrollTo({
animated: true,
y: 0,
x: dimension.width * newIndex,
});
}, [selectedIndex]);
const startInterval = useCallback(() => {
intervalId = setInterval(onSlideChange, 3000);
}, [onSlideChange]);
useEffect(() => {
startInterval();
return () => {
// Clear the interval when component unmounts, otherwise you could have memory leaks
clearInterval(intervalId);
};
}, [onSlideChange]);
const onTouchStart = () => {
// As soon as the user touches the slide, stop the automatic sliding
clearInterval(intervalId);
};
const onTouchEnd = () => {
// As soon as the user stops touching the slide, releases it, start the automatic sliding again
startInterval();
};
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'},
];
const setIndex = event => {
let viewSize = event.nativeEvent.layoutMeasurement.width;
let contentOffset = event.nativeEvent.contentOffset.x;
let carouselIndex = Math.floor(contentOffset / viewSize);
setSelectedIndex(carouselIndex);
};
return (
<View style={{width: dimension.width}}>
<ScrollView
horizontal
ref={scrollRef}
onMomentumScrollEnd={setIndex}
showsHorizontalScrollIndicator={false}
onTouchStart={onTouchStart}
onTouchEnd={onTouchEnd}
pagingEnabled>
{carouselImages.map((value, key) => (
<Image
source={{uri: `${value.url}`}}
style={{width: dimension?.width, height: 250, resizeMode: 'cover'}}
PlaceholderContent={<ActivityIndicator />}
/>
))}
</ScrollView>
<View
style={{
flexDirection: 'row',
position: 'absolute',
bottom: 0,
alignSelf: 'center',
}}>
{carouselImages.map((val, key) => (
<Text
key={key}
style={key === selectedIndex ? {color: 'white'} : {color: '#888'}}>
⬤
</Text>
))}
</View>
</View>
);
};
const styles = StyleSheet.create({});
export default HomeCarousel;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.