You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native onPress事件始终传递数组最后索引问题求助

Fix: CheckBox onPress Always Passes Last Index in React Native Swipe Component

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 18:27:49