React Native onPress事件始终传递数组最后索引问题求助
Alright, let's break down what's happening here and fix this frustrating issue.
The Root Cause
The Swipe component you're using renders all cards at once—it just hides non-active ones with opacity: 0. Combined with JavaScript's closure behavior, this is why you're stuck with the last index: when you define the onPress callback inside the map loop, all callbacks end up referencing the same index/i variable. By the time any callback fires, that variable holds the final value from the loop (the last array index).
Your attempts with arrow functions and bind didn't work because even hidden cards are still mounted in the view tree, so their callbacks still hold that stale reference to the loop variable.
Solutions to Try
1. Create a Unique Closure for Each CheckBox
Wrap the CheckBox in an immediately-invoked function expression (IIFE) to capture the current index and i values for each iteration. This ensures each callback gets its own isolated copy of the variables:
{item.options.map(({ option, checked }, i) => { // Wrap in IIFE to lock in current index and i return ( <View key={i}> {((questionIdx, optionIdx) => ( <CheckBox containerStyle={{ backgroundColor: "transparent", borderWidth: 0 }} title={option} checkedIcon='dot-circle-o' uncheckedIcon='circle-o' checked={checked} onPress={() => this.onSelectOption(questionIdx, optionIdx)} /> ))(index, i)} </View> ) })}
2. Only Render the Active Card in the Swipe Component
The cleanest fix is to modify your Swipe component to only render the currently active card, eliminating the closure issue entirely:
renderCards() { const currentItem = this.props.data[this.state.index]; if (!currentItem) return null; return ( <Animated.View key={this.state.index} style={[this.getCardStyle(), styles.cardStyle]} {...this.panResponder.panHandlers} > {this.props.renderCard(currentItem, this.state.index)} </Animated.View> ); }
3. Use Unique Question IDs Instead of Indexes
Indexes are fragile—switch to using your question's unique ID (u_question_id) to target the correct question. This is more robust even if your array order changes:
First, update the onPress to pass the question ID:
onPress={() => this.onSelectOption(item.u_question_id, i)}
Then modify onSelectOption to find the question by ID:
onSelectOption = (questionId, optionIndex) => { // Create a proper copy of the state array to avoid mutating original state const selectedLanguageQuestionsCopy = [...this.state.selectedLanguageQuestions]; // Find the question using its unique ID const targetQuestion = selectedLanguageQuestionsCopy.find(q => q.u_question_id === questionId); if (targetQuestion) { // Uncheck all options first targetQuestion.options.forEach(opt => opt.checked = false); // Check the selected option targetQuestion.options[optionIndex].checked = true; this.setState({ assessmentData: selectedLanguageQuestionsCopy }); } }
Quick Note on State Updates
You're currently making a shallow copy of your state array with const selectedLanguageQuestionsCopy = this.state.selectedLanguageQuestions;—while this works for your case, it's better practice to use the spread operator ([...array]) or slice() to create a new array, so you don't risk mutating the original state directly.
内容的提问来源于stack exchange,提问作者DragonBorn

