React Bootstrap Form.Control默认值未生效问题咨询及改进建议
问题描述
我正在实现点击按钮弹窗为指定学生添加成绩的功能,但遇到一个问题:直接选择下拉框默认显示的“不及格(Poor)”成绩时,该值无法被识别,没办法添加到学生成绩表(数据取自student.firstSemester);但切换到其他成绩再切回“不及格”时就能正常工作。作为开发新手,求改进方案。
相关代码
const GradesTable= ({selectedClass, displayedSubj}) => { let students = selectedClass.students; const {t} = useTranslation(); const [isInEditMode, updateIsInEditMode] = useState(false); const secondTermStartsAt = new Date('2021-02-01T22:00:00.000+0000'); const [currentUser, updateUser] = useState(null); const [isOpenModal, openModal] = useState(false); const [studentNames, setStudentNames] = useState(undefined); const [studentGrade, setGrade] = useState(undefined); const [description, setDescription] = useState(undefined); let allGrades = [ {key : "2", name : t('journal table.grades.poor')}, {key : "3", name : t('journal table.grades.average')}, {key : "4", name : t('journal table.grades.good')}, {key : "5", name : t('journal table.grades.very good')}, {key : "6", name : t('journal table.grades.excellent')}, ]; const setOpenModal = (value, names) => { openModal(value); setStudentNames(names); } useEffect( () => { if(!currentUser){ const user = AuthService.getCurrentUser(); if (user) { updateUser(user); } } if(displayedSubj && students){ setTableData(populateTableData(students)); }}, [displayedSubj, students, currentUser] ); const flatmapArr = (arr) => { return [].concat.apply([],arr); } const saveGrade = (value) => { var grade = { id: null, date: new Date(), description: description, mark: studentGrade, subject: getCurrentSubject(), byWhom: currentUser.teacher }; var currentStudent = tableData.filter(student => student.names === studentNames)[0]; var student = students.filter(stud => stud.id === currentStudent.id); student[0].grades.push(grade); try { StudentService.updateStudent(student[0]); } catch(error) { alert(error.stack); } setOpenModal(false); } const handleGradeChange = (grade) => { setGrade(grade); assignGradeValueToStudent(grade); } const assignGradeValueToStudent = (grade) => { var currentStudent = tableData.filter(student => student.names === studentNames)[0]; if(isEmpty(currentStudent.firstSemester)) { currentStudent.firstSemester = currentStudent.firstSemester + grade; } else if(currentStudent.firstSemester.substring(currentStudent.firstSemester.length-1, currentStudent.firstSemester.length) === studentGrade) { currentStudent.firstSemester = currentStudent.firstSemester.substring(0, (currentStudent.firstSemester.length-1)); if(isEmpty(currentStudent.firstSemester)) { currentStudent.firstSemester = currentStudent.firstSemester + grade; } else { currentStudent.firstSemester = currentStudent.firstSemester + " " + grade; } } else { currentStudent.firstSemester = currentStudent.firstSemester + " " + grade; } } const setCloseModal = () => { debugger; var currentStudent = tableData.filter(student => student.names === studentNames)[0]; if(!isEmpty(currentStudent.firstSemester)) { currentStudent.firstSemester = currentStudent.firstSemester.substring(0, (currentStudent.firstSemester.length-1)); } setOpenModal(false, undefined); } return( <div> {isOpenModal && <Modal.Dialog> <Modal.Header> <Modal.Title> {t('journal table.adding a grade')} <b><i>{studentNames}</i></b> </Modal.Title> </Modal.Header> <Modal.Body> <Form.Row> <Form.Group as={Col} md="3" controlId="empty" /> <Form.Group as={Col} md="6" controlId="exampleForm.ControlSelect1"> <Form.Label>{t('journal table.grade')}</Form.Label> <Form.Control name='grade' as="select" defaultValue={''} onChange={(event) => handleGradeChange(event.target.value)}> {allGrades && allGrades.map(grade => <option key={grade.key} value={grade.key}> {grade.name} </option> )} </Form.Control> </Form.Group> </Form.Row> <Form.Row> <Form.Group as={Col} md="2" controlId="empty" /> <Form.Group as={Col} md="8" controlId="exampleForm.ControlInput1"> <Form.Label>{t('journal table.description')}</Form.Label> <Form.Control name='description' type="text" onChange={(event) => setDescription(event.target.value)}/> </Form.Group> </Form.Row> </Modal.Body> <Modal.Footer> <Button variant="secondary" onClick={() => setCloseModal(false, undefined)}> {t('journal table.close')} </Button> <Button variant="primary" onClick={(val) => saveGrade(val)}> {t('journal table.save changes')} </Button> </Modal.Footer> </Modal.Dialog> } {!isOpenModal && <div> <BootstrapTable keyField="id" data={tableData} columns={columns} hover /> </div> } </div> ); } export default GradesTable;
解决方案
问题根源
下拉框的defaultValue设为'',但页面加载时下拉框默认渲染第一个选项(值为"2"的“不及格”),由于defaultValue不匹配任何选项的value,不会触发onChange事件,导致studentGrade状态始终是初始的undefined,直接保存时拿不到有效成绩值。切换选项后会触发onChange更新状态,切回“不及格”时同样触发事件,所以能正常工作。
1. 同步初始状态与下拉框默认值
把studentGrade的初始状态设为第一个成绩的key("2"),同时将下拉框的defaultValue改为"2",确保弹窗打开时默认选中“不及格”且状态已有值:
// 修改初始状态 const [studentGrade, setGrade] = useState("2"); // 修改下拉框组件 <Form.Control name='grade' as="select" defaultValue="2" onChange={(event) => handleGradeChange(event.target.value)}> {/* 选项渲染逻辑不变 */} </Form.Control>
2. 弹窗打开时重置成绩状态
在打开弹窗的函数里重置成绩为默认值,避免上次选择的成绩残留影响新的添加操作:
const setOpenModal = (value, names) => { openModal(value); setStudentNames(names); setGrade("2"); // 每次打开弹窗都重置为默认的不及格 };
3. 修复状态异步更新的依赖问题
assignGradeValueToStudent函数里原本使用studentGrade状态,但setGrade是异步操作,可能导致拿到旧值,建议直接用函数传入的grade参数:
const assignGradeValueToStudent = (grade) => { var currentStudent = tableData.filter(student => student.names === studentNames)[0]; if(isEmpty(currentStudent.firstSemester)) { currentStudent.firstSemester = currentStudent.firstSemester + grade; } else if(currentStudent.firstSemester.substring(currentStudent.firstSemester.length-1) === grade) { currentStudent.firstSemester = currentStudent.firstSemester.substring(0, currentStudent.firstSemester.length-1); if(isEmpty(currentStudent.firstSemester)) { currentStudent.firstSemester = currentStudent.firstSemester + grade; } else { currentStudent.firstSemester = currentStudent.firstSemester + " " + grade; } } else { currentStudent.firstSemester = currentStudent.firstSemester + " " + grade; } };
4. 可选:添加提交前校验
在saveGrade函数里增加成绩值校验,避免无值提交的情况:
const saveGrade = (value) => { if (!studentGrade) { alert("请选择成绩"); return; } // 原保存逻辑不变 };
内容的提问来源于stack exchange,提问作者FireAndBlood
相关产品推荐
相关产品推荐

