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

React应用持续渲染无视if条件,错题重答功能开发遇阻

问题分析与修复方案

核心问题点

  1. 无限渲染循环:当score === 2时直接调用setState将score重置为0,触发组件重新渲染,此时score不再满足条件,回到正常答题分支;得分再次涨到2时又触发重置,形成循环。
  2. while语句误用:组件渲染函数的职责是返回JSX,while循环会在第一次迭代就直接返回内容,无法实现逐个作答错题的逻辑,且直接修改数组不会触发React状态更新,无法驱动视图变化。
  3. 状态逻辑混乱:仅靠score判断答题模式过于脆弱,没有明确标记「正常答题」和「错题复习」两种状态,导致流程失控。

修复后的完整代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    <title>乘法答题应用</title></head>

    <style>
        .challenge-container {
            text-align: center;
            font-family:sans-serif;
            font-size:55px;
        }

        input {
            font-size:55px;            
        }
        .correct {
            color:green;
        }

        .incorrect {
            color:red;
        }
    </style>
  <body>
    <div id="app"></div>

    <script type="text/babel">
        function App() {
            // 拆分独立状态,避免对象展开的遗漏问题
            const [num1, setNum1] = React.useState(Math.ceil(Math.random() * 10));
            const [num2, setNum2] = React.useState(Math.ceil(Math.random()* 10));
            const [response, setResponse] = React.useState("");
            const [score, setScore] = React.useState(0);
            const [status, setStatus] = React.useState(true);
            const [wrongQuestions, setWrongQuestions] = React.useState([]);
            // 新增模式标记:normal(正常答题)/review(错题复习)
            const [mode, setMode] = React.useState('normal');
            // 复习模式下当前处理的错题索引
            const [currentReviewIndex, setCurrentReviewIndex] = React.useState(0);

            function updateResponse(event) {
                setResponse(event.target.value);
            }

            // 正常答题逻辑
            function handleNormalAnswer() {
                const answer = parseInt(response);
                const correctAnswer = num1 * num2;
                if(answer === correctAnswer){
                    const newScore = score + 1;
                    setScore(newScore);
                    setResponse("");
                    setStatus(true);
                    // 得分达标,切换到复习模式
                    if(newScore === 2) {
                        setMode('review');
                        setCurrentReviewIndex(0);
                    } else {
                        // 生成新题目
                        setNum1(Math.ceil(Math.random() * 10));
                        setNum2(Math.ceil(Math.random()* 10));
                    }
                } else {
                    setScore(score - 1);
                    setResponse("");
                    setStatus(false);
                    // 保存错题
                    setWrongQuestions([...wrongQuestions, [num1, num2]]);
                    // 生成新题目
                    setNum1(Math.ceil(Math.random() * 10));
                    setNum2(Math.ceil(Math.random()* 10));
                }
            }

            // 错题复习逻辑
            function handleReviewAnswer() {
                const currentWrong = wrongQuestions[currentReviewIndex];
                const answer = parseInt(response);
                const correctAnswer = currentWrong[0] * currentWrong[1];
                if(answer === correctAnswer){
                    setStatus(true);
                    setResponse("");
                    const nextIndex = currentReviewIndex + 1;
                    // 所有错题完成,切回正常模式
                    if(nextIndex >= wrongQuestions.length) {
                        setMode('normal');
                        setScore(0);
                        setWrongQuestions([]);
                        setNum1(Math.ceil(Math.random() * 10));
                        setNum2(Math.ceil(Math.random()* 10));
                    } else {
                        setCurrentReviewIndex(nextIndex);
                    }
                } else {
                    setStatus(false);
                    setResponse("");
                    // 答错的错题重新放回队列末尾,确保用户必须掌握
                    const updatedWrongs = [...wrongQuestions];
                    updatedWrongs.push(updatedWrongs[currentReviewIndex]);
                    updatedWrongs.splice(currentReviewIndex, 1);
                    setWrongQuestions(updatedWrongs);
                }
            }

            function inputKeyPress(event) {
                if(event.key === "Enter"){
                    mode === 'normal' ? handleNormalAnswer() : handleReviewAnswer();
                }
            }

            // 根据模式渲染对应视图
            if(mode === 'review') {
                const currentWrong = wrongQuestions[currentReviewIndex];
                return (
                    <div className="challenge-container">
                        <p>Let's solve the mistakes!</p>
                        <p className={status ? "correct" : "incorrect"}>{currentWrong[0]} * {currentWrong[1]}</p>
                        <input type="text" className="answer-box" value={response} onKeyPress={inputKeyPress} onChange={updateResponse}/>
                        <p>Score: {score}</p>    
                    </div>
                )
            } else {
                return (
                    <div className="challenge-container">
                        <p className={status ? "correct" : "incorrect"}>{num1} * {num2}</p>
                        <input type="text" className="answer-box" value={response} onKeyPress={inputKeyPress} onChange={updateResponse}/>
                        <p>Score: {score}</p>    
                    </div>
                );
            }
        }

        ReactDOM.render(<App />, document.querySelector("#app"));
    </script>
  </body>
</html>

关键修改说明

  • 拆分状态:将原单一state拆分为多个独立useState,避免对象展开时遗漏属性,让状态管理更清晰。
  • 明确模式标记:新增mode状态区分两种答题模式,彻底解决原逻辑中靠score判断的脆弱性。
  • 复习进度跟踪:用currentReviewIndex管理当前处理的错题,完成一个后移动索引,直到所有错题处理完毕。
  • 修复渲染循环:不在渲染函数中直接调用setState,而是在答题逻辑中根据条件切换模式,彻底避免无限渲染。
  • 优化错题处理:复习时答错的错题会重新放回队列末尾,确保用户必须掌握该知识点后才能回到正常答题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:02:08