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
相关产品推荐
相关产品推荐

