求助:使用Formik验证测验系统中嵌套数组的动态问题与答案
Formik嵌套FieldArray验证解决方案
针对你用Formik管理测验问题时的嵌套验证需求,修改后的validate函数如下,能正确处理每个问题的答案文本非空校验,同时避免添加新问题时的报错:
const validate = (fields: QuestionFields) => { const errors: any = { questions: [] }; // 提前初始化questions错误数组 fields.questions.forEach((q, questionIndex) => { // 先为当前问题初始化错误对象,避免后续赋值时报错 errors.questions[questionIndex] = {}; // 验证问题文本 if (!q.questionText?.trim()) { errors.questions[questionIndex].questionText = '问题内容不能为空'; } // 初始化答案错误数组 errors.questions[questionIndex].answers = []; let hasEmptyAnswer = false; let hasCorrectChoice = false; // 遍历每个答案,验证文本非空并检查是否有正确选项 q.answers.forEach((answer, answerIndex) => { // 验证答案文本 if (!answer.text?.trim()) { errors.questions[questionIndex].answers[answerIndex] = { text: '答案内容不能为空' }; hasEmptyAnswer = true; } else { // 无错误时也要初始化空对象,避免渲染时访问undefined报错 errors.questions[questionIndex].answers[answerIndex] = {}; } // 标记是否有正确选项 if (answer.isCorrectChoice) { hasCorrectChoice = true; } }); // 验证是否至少有一个正确选项 if (!hasCorrectChoice) { errors.questions[questionIndex].noCorrectAnswer = '至少需要选择一个正确答案'; } }); // 过滤掉没有任何错误的问题,减少不必要的错误对象 errors.questions = errors.questions.map((questionErrors: any) => { const hasErrors = Object.keys(questionErrors).some(key => { if (key === 'answers') { return questionErrors.answers.some((ansErr: any) => Object.keys(ansErr).length > 0); } return !!questionErrors[key]; }); return hasErrors ? questionErrors : undefined; }); return errors; };
关键处理说明:
- 提前初始化错误结构:直接在
errors里初始化questions数组,并且遍历每个问题时先创建对应的错误对象,避免添加新问题时因errors.questions[index]不存在导致的报错。 - 答案错误的精细化管理:为每个答案单独创建错误对象,渲染时可以通过
form.errors.questions?.[questionIndex]?.answers?.[answerIndex]?.text精准获取单个答案的错误提示。 - 空值处理:使用
trim()过滤空格,避免用户只输入空格被判定为有效内容;无错误的答案也初始化空对象,防止渲染时访问undefined报错。 - 正确选项校验:新增
hasCorrectChoice标记,确保每个问题至少有一个正确选项,并在问题级添加对应的错误提示。
渲染时的错误使用示例:
在FieldArray的渲染逻辑中,可以这样获取并展示错误:
<FieldArray name="questions"> {({ push, remove }) => ( fields.questions.map((question, questionIndex) => ( <div key={questionIndex}> {/* 问题文本错误 */} {errors.questions?.[questionIndex]?.questionText && ( <span className="error">{errors.questions[questionIndex].questionText}</span> )} {/* 正确选项错误 */} {errors.questions?.[questionIndex]?.noCorrectAnswer && ( <span className="error">{errors.questions[questionIndex].noCorrectAnswer}</span> )} {/* 答案输入框及错误 */} {question.answers.map((answer, answerIndex) => ( <div key={answerIndex}> <Field name={`questions[${questionIndex}].answers[${answerIndex}].text`} /> {errors.questions?.[questionIndex]?.answers?.[answerIndex]?.text && ( <span className="error">{errors.questions[questionIndex].answers[answerIndex].text}</span> )} <Field type="checkbox" name={`questions[${questionIndex}].answers[${answerIndex}].isCorrectChoice`} /> </div> ))} </div> )) )} </FieldArray>
内容的提问来源于stack exchange,提问作者Abdi
相关产品推荐
相关产品推荐

