[英]how can I make a custom carousel or image slide in react native without using any npm packages
我在不使用任何包的情況下在本機反應中制作自定義圖像輪播或圖像滑塊,問題是底部的點指示器在 3 秒間隔后變化良好,但圖像不會自動滑動。 有一些我找不到的小問題。 如果您可以在不更改大部分代碼的情況下幫助解決此問題,那就太好了。 提前致謝。
這是完整的組件代碼。
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;
由於兩件事,您的圖像沒有更新:
// You're just defining the function here and not actually calling it
() => {
scrollRef.current.scrollTo({
animated: true,
y: 0,
x: dimension.width * selectedIndex,
});
};
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
}, []);
我對改進/修復的建議是:
useEffect
回調中更新幻燈片並應用帶有selectedIndex
依賴項的useCallback
掛鈎。 您還應該在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> );
這是完整的工作代碼。
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.