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

React单选测验应用中可复用映射组件变更时如何更新state

问题解答

  • 首先回答你问的组件是否要放同一文件的问题:两个组件放在同一文件对解决逻辑问题没有帮助,只是开发阶段可以减少文件切换成本,方便调试,逻辑上无论是否同文件实现思路都是一致的。
  • 核心实现思路:父组件QuizEdit维护所有题目状态,新增统一的状态更新方法,通过props把更新方法传递给子组件EditableQuestion,子组件所有输入项触发修改时,把当前题目ID、修改的字段、新值回传给父组件执行更新即可。

修改后的父组件QuizEdit代码

class QuizEdit extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            title : '',
            time : null,
            questionNr : 2,
            questions : [
                {
                    questionId : 1,
                    text : "This is a test question text",
                    ans1 : "Possible answer 1",
                    ans2 : "Possible answer 2",
                    ans3 : "Possible answer 3",
                    ans4 : "Possible answer 4",
                    correctAnswer : 1,
                    points: 5
                },
                {
                    questionId : 2,
                    text : "This is the second test question text",
                    ans1 : "Possible answer 1",
                    ans2 : "Possible answer 2",
                    ans3 : "Possible answer 3",
                    ans4 : "Possible answer 4",
                    correctAnswer : 2,
                    points: 10
                }
            ]
        }
        // 绑定方法this指向
        this.handleQuestionUpdate = this.handleQuestionUpdate.bind(this);
    }

    // 新增题目状态统一更新方法
    handleQuestionUpdate(questionId, field, value) {
        this.setState(prevState => ({
            questions: prevState.questions.map(q => {
                if(q.questionId === questionId) {
                    return {
                        ...q,
                        [field]: value
                    }
                }
                return q;
            })
        }))
    }

    render(){
        const {questions} = this.state;
        return(
            <div className='quiz-edit'>
                <div className='quiz-question'>{
                        questions.map((question) => (
                            <EditableQuestion 
                                key={question.questionId} 
                                {...question}
                                onUpdate={this.handleQuestionUpdate}
                            />
                        ))
                }
                </div>
            </div>
        )
    }
}

export default QuizEdit;

修改后的EditableQuestion组件代码

const EditableQuestion = ({questionId, correctAnswer, points, text, ans1, ans2, ans3, ans4, onUpdate, ...otherProps}) => (
    <div className='editable-question'>
        <div className='question-text'>
            <textarea 
                name="text" 
                cols="30" 
                rows="5" 
                value={text}
                onChange={(e) => onUpdate(questionId, 'text', e.target.value)}
            ></textarea>
        </div>
        <div className='question-answers'>
            <div className='answer'>
                <input 
                    type='radio'  
                    name={questionId} 
                    checked={1 === correctAnswer}
                    onChange={() => onUpdate(questionId, 'correctAnswer', 1)}
                />
                <input 
                    type='text' 
                    value={ans1}
                    onChange={(e) => onUpdate(questionId, 'ans1', e.target.value)}
                />
            </div>
            <div className='answer'>
                <input 
                    type='radio'  
                    name={questionId} 
                    checked={2 === correctAnswer}
                    onChange={() => onUpdate(questionId, 'correctAnswer', 2)}
                />
                <input 
                    type='text' 
                    value={ans2}
                    onChange={(e) => onUpdate(questionId, 'ans2', e.target.value)}
                />
            </div>
            <div className='answer'>
                <input 
                    type='radio'  
                    name={questionId} 
                    checked={3 === correctAnswer}
                    onChange={() => onUpdate(questionId, 'correctAnswer', 3)}
                />
                <input 
                    type='text' 
                    value={ans3}
                    onChange={(e) => onUpdate(questionId, 'ans3', e.target.value)}
                />
            </div>
            <div className='answer'>
                <input 
                    type='radio'  
                    name={questionId} 
                    checked={4 === correctAnswer}
                    onChange={() => onUpdate(questionId, 'correctAnswer', 4)}
                />
                <input 
                    type='text' 
                    value={ans4}
                    onChange={(e) => onUpdate(questionId, 'ans4', e.target.value)}
                />
            </div>
        </div>
        <div className='points'>
        <input 
            type='text' 
            value={points}
            onChange={(e) => onUpdate(questionId, 'points', e.target.value)}
        />
        <span>points</span>
        </div>
    </div>
)

export default EditableQuestion;

额外说明

  • 原来的defaultValue/defaultChecked改成了受控的value/checked,保证视图和父组件的状态完全同步
  • 所有输入项的onChange事件都会把当前修改的信息回传给父组件的统一更新方法,避免了重复写多个更新函数的冗余
  • 分值如果要求是数字,可以在更新的时候加一层转换,比如把e.target.value改成Number(e.target.value) || 0,避免字符串类型的数值存入状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 20:39:00