简体   繁体   English

如何在不使用任何 npm 包的情况下在本机反应中制作自定义轮播或图像幻灯片

[英]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:由于两件事,您的图像没有更新:

  1. You're setting the update in an anonymous function which isn't being called:您正在将更新设置在未被调用的匿名 function 中:
// You're just defining the function here and not actually calling it
() => {
  scrollRef.current.scrollTo({
    animated: true,
    y: 0,
    x: dimension.width * selectedIndex,
  });
};
  1. Your 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:我对改进/修复的建议是:

  1. Extract the function to update the slides out of useEffect callback and apply a useCallback hook with selectedIndex dependency.提取 function 以从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
};
  1. Another thing I would suggest you to make this carousel complete is to clear the interval/stop the automatic sliding as soon as the user starts sliding, otherwise it would cause weird behavior and slides getting out of control.我建议您完成此轮播的另一件事是在用户开始滑动时清除间隔/停止自动滑动,否则会导致奇怪的行为和幻灯片失控。 You can restart the automatic sliding as soon as the user has finished his sliding action:用户完成滑动操作后,您可以重新启动自动滑动:
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.

相关问题 如何在React Native中制作没有自动播放的轮播 - How to make Carousel without autoplay in react native 我不是Java语言专家..如何使Jquery Carousel的图像幻灯片一张一张地滑动? - I'm Not a Javascript Expert .. How Can I Make a Jquery Carousel's Image Slide One By One? 如何使用react-native-snap-carousel在react native中获取和传递活动幻灯片的详细信息 - How to get and pass the details of the active slide in react native using react-native-snap-carousel 如何在本机反应中制作带有钩子的无限图像轮播 - how to make an infinite image carousel with hooks in react native 如何在不使用“链接”的情况下将自定义 fonts 添加到 React Native 中? - How can custom fonts be added in React Native without using "link"? 如何使用 react-responsive-carousel 和 react-image-magnifiers 自定义缩略图的 map 值? - How do I map values for custom thumbnails using react-responsive-carousel and react-image-magnifiers? 如何在不使用JSX的情况下在React Native中创建组件? - How do I make components in React Native without using JSX? 如何在不显示超链接的情况下制作可点击的图像? - how can I make a clickable image in react without showing the hyperlinks? 如何在 react-native-snap-carousel 中使轮播循环? - how to make carousel circular in react-native-snap-carousel? 我可以用 React Native 组件做轮播吗? - Can I do carousel with components React Native?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM