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

React实现问答组件切换上下题时持久化保留已选答案状态

React 问答应用题目切换+状态持久化实现

核心实现思路:

  • 所有公共状态(当前题目序号、所有题的已选答案)统一放在父组件维护,避免子组件单独存状态导致切换卸载时数据丢失
  • 同一时间只渲染当前序号对应的题目组件,不需要一次性加载全部题目
  • 父组件通过props给子组件传递当前题的已选答案、更新答案的回调方法,子组件只负责渲染和触发选中事件
  • 切换按钮做边界判断,避免超出题目序号范围
  • 子组件渲染选项时,对比当前选项值和已传入选中值,匹配时给div添加selected类名

第一步:修改父组件 Questions.js

引入useState做状态管理,改造后的代码如下:

import React, { useState } from "react";
import Qustionone from "./qustionone";
import Qustiontwo from "./qustiontwo";
import Qustionthree from "./qustionthree";
import Qustionfour from "./qustionfour";

// 按题目顺序维护组件列表,索引对应题目序号0-3
const questionList = [Qustionone, Qustiontwo, Qustionthree, Qustionfour];

function Questions() {
    // 当前展示的题目索引,默认显示第一题
    const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
    // 存储所有题目的答案,键为题目索引,值为选中的选项标识
    const [answerMap, setAnswerMap] = useState({});

    // 上一题切换逻辑
    const goPrev = () => {
        if (currentQuestionIndex > 0) {
            setCurrentQuestionIndex(currentQuestionIndex - 1);
        }
    };

    // 下一题切换逻辑
    const goNext = () => {
        if (currentQuestionIndex < questionList.length - 1) {
            setCurrentQuestionIndex(currentQuestionIndex + 1);
        }
    };

    // 更新对应题目的选中答案
    const changeAnswer = (qIndex, optionValue) => {
        setAnswerMap(prev => ({
            ...prev,
            [qIndex]: optionValue
        }));
    };

    // 获取当前需要渲染的题目组件
    const CurrentQuestionComp = questionList[currentQuestionIndex];

    return (
        <div>
            <h1>Question and Answer Program</h1>
            <CurrentQuestionComp
                selected={answerMap[currentQuestionIndex]}
                onSelect={(val) => changeAnswer(currentQuestionIndex, val)}
            />
            {/* 第一题时禁用上一页按钮 */}
            <button onClick={goPrev} disabled={currentQuestionIndex === 0}>previous</button>
            {/* 最后一题时可根据需求替换为提交按钮,这里暂时禁用下一页 */}
            <button onClick={goNext} disabled={currentQuestionIndex === questionList.length - 1}>next</button>
        </div>
    );
}

export default Questions;

第二步:改造题目子组件

以Qustionone.js为例,其余3个题目组件改造逻辑完全一致,仅需要替换题目内容和选项内容:

import React from "react";

function Qustionone({ selected, onSelect }) {
    // 维护当前题的选项列表,每个选项配置唯一值和展示文本
    const options = [
        { value: "q1-1", text: "Answer1" },
        { value: "q1-2", text: "Answer2" },
        { value: "q1-3", text: "Answer3" }
    ];

    return (
        <div>
            <p>Qustion 1 ?</p>
            {options.map(opt => (
                <div
                    key={opt.value}
                    // 选项值和已选值匹配时,添加selected类名
                    className={selected === opt.value ? "selected" : ""}
                    // 点击选项时触发父组件传入的回调,更新答案
                    onClick={() => onSelect(opt.value)}
                >
                    {opt.text}
                </div>
            ))}
        </div>
    );
}

export default Qustionone;

其余子组件修改注意事项

  • 每个子组件都需要接收selected和onSelect两个props,不需要自己维护内部选中状态
  • 每个题的选项value保证全局唯一即可,比如第二题选项值可设为q2-1/q2-2/q2-3,避免和其他题选项冲突
  • 自行编写.selected类对应的CSS样式,比如高亮背景、加粗边框等效果即可

实现后切换题目时,所有已选答案都存在父组件的answerMap状态中,不会因为子组件卸载丢失,切回历史题目时会自动匹配已选值添加选中样式,完全符合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:15:30