javascript - 如何在 React Native 中制作带有钩子(Hook)的无限图像轮播

标签 javascript react-native react-hooks

我在 React Native 中使用钩子(Hook)和 javascript 制作无限图像轮播。

我几乎完成了代码,轮播也工作得非常好,但轮播下方的事件点比图像运行得更快。我已经尝试了几件事,但遗憾的是没有成功。

提前致谢。

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;


作为 props 传递给这个组件的数据是

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'},
];

最佳答案

哦哦,我自己修好了 这是完美的工作代码完整代码。 😄

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;

关于javascript - 如何在 React Native 中制作带有钩子(Hook)的无限图像轮播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67337104/

相关文章:

javascript - 将父目录中的文件导入 React Native 应用程序

react-native - 带钩子(Hook)的 apploading splashscreen

javascript - 从页面顶部滚动之前页面会闪烁到 anchor

javascript - 动态更新 HTMLCollections 的优雅方式

javascript - 在 React Native 中,是否可以在 Pan Responder 的 onStartShouldSetPanResponder 中检测到滑动与点击?

javascript - 动画 : `useNativeDriver` was not specified issue of ReactNativeBase Input

javascript - 在 document.ready 中设置隐藏字段值并在 pageload 事件中获取其值

javascript - 尽管获得了 promise ,但未处理的 promise 拒绝

javascript - useState 不更新其值

javascript - 使用 useEffect 钩子(Hook)获取数据时,React 组件不会在 URL 参数更改时重新渲染