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

为什么React Native乘法练习项目中compareQA的qaIndex仅返回0或-1

问题排查与修复方案

存在的问题

  • React state更新是异步操作,set后无法立刻读取最新值
    1. createQuestionsArray函数中循环调用setQuestionsArray、setAnswersArray后立刻执行askQuestion,此时state还未完成更新,questionsArray仍是初始空数组,随机取值会得到undefined,后续indexOf查找undefined自然返回-1。
    2. compareQA函数中刚执行setQAIndex就立刻用qaIndex取值,此时拿到的是上一次渲染的旧值,不是刚计算出的索引,导致比对逻辑永远不生效。
  • 直接修改state原值违反React不可变原则
    直接对state中的questionsArray、answersArray调用splice原地修改数组,会导致React状态更新异常。
  • 数据类型不匹配
    TextInput返回的输入值是字符串类型,和answersArray中存储的数字直接比对,存在隐式转换的潜在风险。

修复后的代码示例

import React, { useState, useEffect } from "react";
import { StyleSheet, Text, View, Pressable, TextInput } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { NavigationContainer } from '@react-navigation/native';
import styles from '../Components/AppStyle';
import {LittleSpace05,LittleSpace1, LittleSpace4} from '../Components/LittleSpace';
import changeSize from '../Components/ChangeSize';

function RouletteExercice1 ({ route, navigation }){

  const { multiplyArray, multBy} = route.params;

  const [adaptTitleFontSize, setAdaptTitleFontSize] = useState({
    fontSize: 16,
  });
  const [adaptButtonFontSize, setAdaptButtonFontSize] = useState({
    fontSize: 16,
  });

  const getSize = (event, divide, thing) => {
    if (thing == 'title') {
      setAdaptTitleFontSize(changeSize(event.nativeEvent.layout, divide))
    } else {
      setAdaptButtonFontSize(changeSize(event.nativeEvent.layout, divide))
    }

   };

   const [questionsArray,setQuestionsArray] = useState([]);
   const [answersArray,setAnswersArray] = useState([]);
   const [mQuestion,setMQuestion] = useState();
   const [textInputAnswer, setTextInputAnswer] = useState();

  useEffect(() => {
    createQuestionsArray();
  },[]);

  // 监听题目数组变化,有值时抽第一道题
  useEffect(() => {
    if(questionsArray.length > 0) {
      askQuestion()
    }
  }, [questionsArray])

   function createQuestionsArray() {
       // 先生成完整的题目、答案数组,一次性更新state
       const questions = []
       const answers = []
       let m = 0;
       while (m < multiplyArray.length) {
         let b = 1;
         while (b < multBy+1) {
           let quest = multiplyArray[m]+'x'+b;
           let rep = multiplyArray[m]*b;
           questions.push(quest);
           answers.push(rep);
           b++
         }
        m++
       }
       setQuestionsArray(questions);
       setAnswersArray(answers);
   }

   function askQuestion(){
       setMQuestion(questionsArray[Math.floor(Math.random()*questionsArray.length)]);
   }

   function compareQA(){
     // 直接在本地计算当前索引,不需要存到state
     const currentIndex = questionsArray.indexOf(mQuestion);
     if(currentIndex === -1) return
     // 输入转数字后再做严格比对
     if (answersArray[currentIndex] === Number(textInputAnswer)) {
       // 生成新数组更新state,不修改原值
       const newQuestions = [...questionsArray]
       const newAnswers = [...answersArray]
       newQuestions.splice(currentIndex,1);
       newAnswers.splice(currentIndex,1);
       setQuestionsArray(newQuestions);
       setAnswersArray(newAnswers);
       console.log(currentIndex);
       setTextInputAnswer('')
       // 还有剩余题目就抽下一道
       if(newQuestions.length > 0) {
        setMQuestion(newQuestions[Math.floor(Math.random()*newQuestions.length)]);
       } else {
        alert('所有题目已完成!')
       }
     } else {
      alert('答案错误,请重试')
     }
   }

  return(
    <View  style={{ flex: 1, flexDirection: 'column'}}>
      <StatusBar style="auto" />
      <View style={{flex: 1}}>
      </View>
      <View style={{flex: 4, alignItems: 'center', justifyContent: 'center'}}>
        <LittleSpace1/>
        <LittleSpace1/>
        <View onLayout={(event) => {getSize(event,2,'title')}} style={[styles.setViewRE1, {alignItems: 'center'}]}>
          <Text style={[styles.textExercice, adaptTitleFontSize,{fontWeight: 'bold'}]}>{mQuestion}</Text>
        </View>
        <LittleSpace05/>
        <View  style={[styles.setViewRE1, {alignItems: 'center'}]}>
          <Text style={[styles.textExercice, adaptTitleFontSize,{fontWeight: 'bold'}]}>=</Text>
        </View>
        <LittleSpace05 />
        <View onLayout={(event) => {getSize(event, 3,'button')}} style={styles.setViewRE1}>
          <LittleSpace4/>
          <TextInput
            onChangeText={text => setTextInputAnswer(text.replace(/[^0-9]/g, ''))}
            value={textInputAnswer}
            placeholder=" perso"
            textAlign={'center'}
            keyboardType="numeric"
            style={[ styles.inputRE1, adaptButtonFontSize]}
            type='number'
          />
          <LittleSpace1/>
          <Pressable style={styles.buttonRE1} onPress={() => {compareQA();}} >
            <Text style={[styles.textExercice, adaptButtonFontSize]}>OK</Text>
          </Pressable>
          <LittleSpace1/>
        </View>
        <LittleSpace1/>
        <LittleSpace1/>
        <LittleSpace4/>
      </View>
      <View style={{flex: 1,}}>
      </View>
    </View>
  )

}

export default RouletteExercice1;

内容的提问来源于stack exchange,提问作者Sevlac

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 05:15:08