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

React问答应用:实现答案点击选中保持及ID重复问题修复

问题修复与实现方案

1. 解决答案项ID重复问题

你当前用index作为答案列表项的key,且点击时传递index,但每个题目下的答案index都是0、1、2、3,导致不同题目的答案无法区分。解决方法:

  • 用题目ID+答案文本作为唯一key,确保每个答案项的key全局唯一
  • 点击时传递题目ID和当前答案文本,明确标记是哪道题的哪个选项被点击

2. 实现答案选中状态切换

需要在每个题目对象中添加selectedAnswer字段跟踪用户选择,点击时切换选中状态:

修改状态初始化

在fetchQuiz中,给每个题目对象新增selectedAnswer: null:

const updated = randomQuiz.map((item) => ({
    ...item,
    selectedAnswer: null, // 跟踪用户选中的答案
}));

实现点击切换逻辑

更新answerClicked函数,根据题目ID和答案文本切换选中状态:

const answerClicked = (questionId, answer) => {
    setQuiz(prevQuiz => prevQuiz.map(quizItem => {
        if (quizItem.id === questionId) {
            // 若当前选中的就是该答案则取消选中,否则设置为选中
            return {
                ...quizItem,
                selectedAnswer: quizItem.selectedAnswer === answer ? null : answer
            };
        }
        return quizItem;
    }));
};

渲染时添加选中样式

生成答案列表项时,判断当前答案是否为该题选中项,添加selected类:

const answerElements = item.answers.map((answer) => (
    <li
        key={`${item.id}-${answer}`} // 唯一key
        className={`answer ${item.selectedAnswer === answer ? 'selected' : ''}`}
        onClick={() => answerClicked(item.id, answer)}
    >
        {answer}
    </li>
));

配套CSS样式:

.answer.selected {
    background-color: #4285F4;
    color: white;
    /* 可按需添加边框、内边距等样式 */
}

3. 统一检查答案实现

添加isChecked状态标记是否已检查答案,点击按钮后显示对错结果并禁用后续选择:

添加检查状态

const [isChecked, setIsChecked] = React.useState(false);

检查答案逻辑

实现检查按钮的点击事件:

const checkAnswers = () => {
    setIsChecked(true);
    // 统计答对数量(可选)
    const correctCount = quiz.filter(item => item.selectedAnswer === item.correctAnswer).length;
    console.log(`答对了${correctCount}题`);
};

渲染时显示对错结果

修改答案列表项渲染逻辑,根据检查状态显示正确/错误样式:

const answerElements = item.answers.map((answer) => {
    let answerClass = 'answer';
    if (isChecked) {
        if (answer === item.correctAnswer) {
            answerClass += ' correct'; // 正确答案样式
        } else if (answer === item.selectedAnswer) {
            answerClass += ' wrong'; // 用户选错的样式
        }
    } else if (item.selectedAnswer === answer) {
        answerClass += ' selected'; // 未检查时的选中样式
    }

    return (
        <li
            key={`${item.id}-${answer}`}
            className={answerClass}
            onClick={() => !isChecked && answerClicked(item.id, answer)} // 检查后禁用点击
        >
            {answer}
        </li>
    );
});

配套CSS样式:

.answer.correct {
    background-color: #34A853;
    color: white;
}
.answer.wrong {
    background-color: #EA4335;
    color: white;
}

更新检查按钮

<button onClick={checkAnswers} disabled={isChecked}>
    {isChecked ? '已检查答案' : '检查答案'}
</button>

完整修改后的组件代码

import React from "react";
import { Link } from "react-router-dom";

export default function Game() {
    const [quiz, setQuiz] = React.useState([]);
    const [isChecked, setIsChecked] = React.useState(false);

    function shuffle(array) {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
    }

    const fetchQuiz = async () => {
        const res = await fetch(
            "https://the-trivia-api.com/api/questions?limit=5"
        );
        const randomQuiz = await res.json();
        const updated = randomQuiz.map((item) => ({
            ...item,
            selectedAnswer: null, // 跟踪用户选中的答案
        }));

        const shuffledQuiz = updated.map((item) => {
            const answers = [...item.incorrectAnswers, item.correctAnswer];
            const shuffledAnswers = shuffle(answers);
            return { ...item, answers: shuffledAnswers };
        });

        setQuiz(shuffledQuiz);
    };

    React.useEffect(() => {
        fetchQuiz();
    }, []);

    const answerClicked = (questionId, answer) => {
        setQuiz(prevQuiz => prevQuiz.map(quizItem => {
            if (quizItem.id === questionId) {
                return {
                    ...quizItem,
                    selectedAnswer: quizItem.selectedAnswer === answer ? null : answer
                };
            }
            return quizItem;
        }));
    };

    const checkAnswers = () => {
        setIsChecked(true);
        const correctCount = quiz.filter(item => item.selectedAnswer === item.correctAnswer).length;
        console.log(`答对了${correctCount}题`);
    };

    let block = quiz.map((item) => {
        const answerElements = item.answers.map((answer) => {
            let answerClass = 'answer';
            if (isChecked) {
                if (answer === item.correctAnswer) {
                    answerClass += ' correct';
                } else if (answer === item.selectedAnswer) {
                    answerClass += ' wrong';
                }
            } else if (item.selectedAnswer === answer) {
                answerClass += ' selected';
            }

            return (
                <li
                    key={`${item.id}-${answer}`}
                    className={answerClass}
                    onClick={() => !isChecked && answerClicked(item.id, answer)}
                >
                    {answer}
                </li>
            );
        });

        return (
            <div key={item.id} className="quiz_block">
                <h1 className="quiz_question">{item.question}</h1>
                <ul className="quiz_answers">{answerElements}</ul>
            </div>
        );
    });

    return (
        <main>
            <div className="game_container">
                {block}

                <div className="footer">
                    <button onClick={checkAnswers} disabled={isChecked}>
                        {isChecked ? '已检查答案' : '检查答案'}
                    </button>
                </div>
            </div>
        </main>
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:07:52