React表单提交后无法重新渲染问题求助
问题诊断与修复
点击提交无反应的核心原因是表单验证未通过,但没有任何错误提示,导致你误以为提交操作没触发。以下是具体问题点和修复方案:
1. 缺少验证错误反馈
你的表单配置了Zod验证,但没有在界面上显示错误信息。当用户输入不符合规则(比如名字太短、没选课程、数字为空或超出范围)时,handleSubmit的回调不会执行,页面自然没有变化。
修复:添加错误显示逻辑
在StudentGradingEvaluationForm.tsx中,从useForm解构formState.errors,然后在每个表单控件下方添加错误提示:
import { z } from "zod"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import courses from "./Courses"; const schema = z.object({ name: z .string() .min(3, { message: "姓名至少需要3个字符" }), number: z.coerce.number() .min(0, { message: "分数不能小于0" }) .max(100, { message: "分数不能超过100" }), courses: z.enum(courses, { errorMap: () => ({ message: "请选择课程" }), }), }); export type StudentFormData = z.infer<typeof schema>; interface Props { onSubmit: (data: StudentFormData) => void; } const StudentGradingEvaluationForm = ({ onSubmit }: Props) => { const { register, handleSubmit, formState: { errors } } = useForm<StudentFormData>({ resolver: zodResolver(schema), }); return ( <form onSubmit={handleSubmit((data) => { onSubmit(data); })} > <div className="mb-3"> <label htmlFor="studentName" className="form-label"> 学生姓名 </label> <input id="studentName" type="text" className={`form-control ${errors.name ? 'is-invalid' : ''}`} {...register("name")} /> {errors.name && <div className="invalid-feedback">{errors.name.message}</div>} </div> <div className="mb-3"> <label htmlFor="courseName" className="form-label"> 课程名称 </label> <div> <select id="courseName" className={`form-select ${errors.courses ? 'is-invalid' : ''}`} {...register("courses")} > <option value="" disabled>请选择课程</option> {courses.map((course) => ( <option key={course} value={course}> {course} </option> ))} </select> </div> {errors.courses && <div className="invalid-feedback">{errors.courses.message}</div>} </div> <div className="mb-3"> <label htmlFor="number" className="form-label"> 输入分数 </label> <input id="number" type="number" className={`form-control ${errors.number ? 'is-invalid' : ''}`} {...register("number")} /> {errors.number && <div className="invalid-feedback">{errors.number.message}</div>} </div> <button type="submit" className="btn btn-primary"> 提交 </button> </form> ); }; export default StudentGradingEvaluationForm;
2. 数字输入的验证问题
原代码中z.number()要求输入必须是有效数字,但当输入框为空时,React Hook Form会返回空字符串'',Zod会判定为验证失败。使用z.coerce.number()可以自动将空字符串、非数字值转换为NaN,配合验证规则可以更友好地处理空输入场景。
3. 课程选择的默认选项问题
原代码中默认选项的value=""是空字符串,不符合z.enum(courses)的枚举值要求,导致未选课程时验证失败。修改为<option value="" disabled>请选择课程</option>,既引导用户选择,又避免空值提交。
额外优化:App.tsx中的逻辑简化
可以简化App.tsx中的状态判断,因为formData存在时必然是提交成功的状态,不需要单独维护isFormSubmitted:
import { useState } from "react"; import StudentGradingEvaluationForm, { StudentFormData, } from "./Components/StudentGradingEvaluationForm"; import GPACalculator from "./Components/GPACalculator"; const App = () => { const [formData, setFormData] = useState<StudentFormData | null>(null); const handleFormSubmitted = (data: StudentFormData) => { setFormData(data); }; const resetForm = () => { setFormData(null); }; return ( <> <div style={{ textAlign: "center" }}> <h1>学生GPA计算器</h1> </div> <div> {!formData && ( <StudentGradingEvaluationForm onSubmit={handleFormSubmitted} /> )} </div> {formData && ( <> <button className="btn btn-outline-danger mb-3" onClick={resetForm}> 重置表单 </button> <GPACalculator subject={formData.courses} number={formData.number} name={formData.name} /> </> )} </> ); }; export default App;
修复后,当用户输入不符合规则时,会显示对应的错误提示;验证通过后,页面会正确渲染GPA计算结果。
内容的提问来源于stack exchange,提问作者Hannan Yusuf Khan
相关产品推荐
相关产品推荐

