gpt4 book ai didi

javascript - FlatList scrollToIndex 超出范围

转载 作者:行者123 更新时间:2023-12-03 23:00:47 30 4
gpt4 key购买 nike

我有一个 FlatList,我试图每隔 X 秒滚动一次数据数组的每个索引。现在我的数组中只有两个项目,但可能还有更多。当前代码适用于前两次迭代,但似乎没有正确重置,我得到 scrollToIndex out of range error: index is 2 but maximum is 1 .我认为当 currentIndex>= data.length我的 if声明将 setCurrentIndex回到0,但它似乎不起作用。基本上我要做的是自动循环 Flatlist 中的项目,但每个项目都会暂停几秒钟。

/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import 'react-native-gesture-handler';
import React, {useState, useEffect, useRef} from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator, HeaderBackButton } from '@react-navigation/stack';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
ImageBackground,
Image,
TextInput,
Button,
TouchableNativeFeedback,
TouchableWithoutFeedback,
TouchableOpacity,
Modal,
Pressable,
PanResponder,
FlatList,
Dimensions
} from 'react-native';

import { Immersive } from 'react-native-immersive';

import {
Header,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

import WineList from './screens/WineList';
import Home from './screens/Home';
import Rate from './screens/Rate';
import Thankyou from './screens/Thankyou';

const Stack = createStackNavigator();

const { width: windowWidth, height: windowHeight } = Dimensions.get("window");

const wineclub = require('./images/wineclub.png');
const gaspers = require('./images/gaspers.png');
const qrcode = require('./images/wineclubQR.png');

let ads = [
{
adImg: wineclub,
adTitle: 'Space will be limited so join online today!',
adInfo: ' Upon joining, both clubs will be billed our Trio Pre-Opening Promotion',
qrCodeImg: qrcode
},
{
adImg: gaspers,
adTitle: 'Coming Soon!',
adInfo: 'Gourmet chef designed menu. Stunning views. Modern romantic decor',
qrCodeImg: qrcode
}
]


function AdSlider({data}){

return(

<View style={{alignContent:'center', alignItems:'center', backgroundColor:'#4B4239', height:1400}}>

<Image source={data.adImg} style={{width:640,height:500}} ></Image>

<Text style={{color:'white', fontFamily:'LaoMN', fontSize:30, marginTop:20}}>{data.adTitle}</Text>

<Text style={{color:'white', fontFamily:'LaoMN', fontSize:20, marginTop:20, textAlign:'center'}} > {data.adInfo} </Text>



<View style={{flexDirection:'row', justifyContent:'flex-start', alignContent:'center', alignItems:'center', marginTop:20}}>
<Text style={{fontSize:40, color:'white', padding:20}}>Scan Here </Text>

<Image source={data.qrCodeImg}></Image>
</View>

</View>

)
}

const App: () => React$Node = () => {
Immersive.on()
Immersive.setImmersive(true)

const navigationRef = useRef(null);


const myRef = useRef(null);

const currentIndex = useRef(0);

const [modalVisible, setModalVisible] = useState(false);

const timerId = useRef(false);

const [timeForInactivityInSecond, setTimeForInactivityInSecond] = useState(
5
)



useEffect(() => {
resetInactivityTimeout()
},[])

const panResponder = React.useRef(
PanResponder.create({
onStartShouldSetPanResponderCapture: () => {
// console.log('user starts touch');

setModalVisible(false)
resetInactivityTimeout()
},
})
).current

const resetInactivityTimeout = () => {
clearTimeout(timerId.current)

timerId.current = setTimeout(() => {
// action after user has been detected idle

setModalVisible(true)
navigationRef.current?.navigate('Home');
}, timeForInactivityInSecond * 1000)
}


// for the slider
useEffect(() => {
const timer = setInterval(() => {
currentIndex.current = currentIndex.current === ads.length - 1
? 0
: currentIndex.current + 1;
myRef.current.scrollToIndex({
animated: true,
index: currentIndex.current ,
});
}, 5000);
return () => clearInterval(timer);
}, []);




return (

<NavigationContainer ref={navigationRef} >
<View {...panResponder.panHandlers} style={{ flex:1}}>

<TouchableWithoutFeedback >
<Modal

animationType="slide"
transparent={false}
hardwareAccelerated={false}
visible={modalVisible}

>
<FlatList
ref={myRef}
data={ads}
renderItem={({ item, index }) => {
return <AdSlider key={index} data={item} dataLength={ads.length} />;
}}
pagingEnabled
horizontal
showsHorizontalScrollIndicator={false}

/>


</Modal>
</TouchableWithoutFeedback>
<Stack.Navigator navigationOptions={{headerTintColor: '#ffffff',}} screenOptions={{
headerTintColor: '#ffffff',
cardStyle: { backgroundColor: '#4B4239' },
}} >
<Stack.Screen name="Home"
component={Home} options={{
headerShown: false,
}} />

<Stack.Screen name="WineList" component={WineList} options={{
title: 'Exit',
headerStyle: {
backgroundColor: '#4B4239',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}/>

<Stack.Screen name="Rate" component={Rate} options={{
title: 'Back to Selections',
headerStyle: {
backgroundColor: '#4B4239',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}/>

<Stack.Screen name="Thankyou" component={Thankyou}
options={
{
headerShown: false,
title: 'Home',
headerStyle: {
backgroundColor: '#4B4239',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}/>
</Stack.Navigator>
</View>
</NavigationContainer>

);
};



export default App;

最佳答案

您收到此错误是因为您传递了 item作为dataAdSlider组件,它没有任何 length属性当然因此它返回 undefined对于 data.length并且不计算表达式 currentIndex === data.length - 1它变成currentIndex === undefined - 1因此currentIndex将增加 1没有停止,它将达到 2 的值这是超出范围的。
您的代码有几个问题。

  • 您不应该在另一个组件中包含一个组件,尤其是在使用父组件的效果和状态时。删除 AdSliderApp 之外零件。
  • 您将项目传递为 dataAdSlider而您正试图将其作为 data.length ,很明显它不会工作,因为 dataitem这是一个对象而不是数组。
  • 您不需要使用 AdSlider 中的效果。 , 在 App 中只设置一个效果并更改 currentIndex成为一个 ref 而不是一个状态变量,因为你不需要它改变状态来重新渲染,因为你正在调用 scrollToIndex用于强制列表更新和重新渲染。

  • 使用 state 和 setTimeout 使其工作
    如果你想用 currentIndex 制作代码处于状态(您不需要),您可以在 App 中移动效果组件和更改 data.lengthads.length它会起作用。
    const App: () => React$Node = () => {
    Immersive.on()
    Immersive.setImmersive(true)

    const navigationRef = useRef(null);
    const myRef = useRef(null);
    const [currentIndex, setCurrentIndex] = useState(0);

    useEffect(() => {
    myRef.current.scrollToIndex({
    animated: true,
    index: currentIndex ,
    });
    }, [currentIndex]);

    useEffect(()=> {
    const timer = setTimeout(()=> {
    // Change data.length to ads.length here
    const nextIndex = currentIndex === ads.length - 1
    ? 0
    : currentIndex + 1;
    setCurrentIndex(nextIndex);
    }, 5000);
    return () => clearTimeout(timer);
    }, [currentIndex]);

    ...
    }
    使用 ref 和 setInterval 使其工作
    最好的办法是转换 currentIndex成为引用并使用 setInterval而不是 setTimeout每 5 秒调用一次循环计时器:
    const App: () => React$Node = () => {
    Immersive.on()
    Immersive.setImmersive(true)

    const navigationRef = useRef(null);
    const myRef = useRef(null);
    // Make currentIndex a ref instead of a state variable,
    // because we don't need the re-renders
    // nor to trigger any effects depending on it
    const currentIndex = useRef(0);

    useEffect(() => {
    // Have a timer call the function every 5 seconds using setInterval
    const timer = setInterval(() => {
    // Change data.length to ads.length here
    currentIndex.current = currentIndex.current === ads.length - 1
    ? 0
    : currentIndex.current + 1;
    myRef.current.scrollToIndex({
    animated: true,
    index: currentIndex.current,
    });
    }, 5000);
    return () => clearInterval(timer);
    }, []);

    ...
    }
    您可以查看有效的 Expo Snack here .

    关于javascript - FlatList scrollToIndex 超出范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65895710/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com