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

求助:使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 09:53:16