【问题标题】:Validating array of strings in React在 React 中验证字符串数组
【发布时间】:2021-11-01 16:05:50
【问题描述】:

我有一个包含一系列电子邮件的表单。数组没有大小限制。我需要检查数组中的每个元素都是有效的电子邮件。用户应该能够向数组中添加新元素,并且应该至少有一封电子邮件,并且每个新元素都应该有一个有效的电子邮件,并且每封电子邮件都应该是唯一的。我希望只有在用户第一次提交表单后才能进行验证。验证电子邮件列表的正确方法应该是什么?

我正在使用 Ant Design 组件,并将无效电子邮件的索引列表保留为 invalidArrayIndexes,以便我可以在每个无效行上显示错误。当我添加新元素时,我无法收到所需的消息(“请输入您的电子邮件!”),并且当我添加或删除新元素时,已验证的索引列表变得混杂。我不确定这是否是在反应中验证字符串列表的正确方法。这是我到目前为止所做的:

import { Button, Form, Input } from "antd";
import { useState } from "react";

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

const isValidEmail = (str) => {
  return emailRegex.test(str);
};

const MyForm = () => {
  const [emails, setEmails] = useState([""]);
  const [invalidArrayIndexes, setInvalidArrayIndexes] = useState([]);
  const [firstSubmit, setFirstSubmit] = useState(false);

  const addEmail = () => {
    const updatedEmails = [...emails];
    updatedEmails.push("");
    setEmails(updatedEmails);
  };

  const removeEmail = (index) => {
    const updatedEmails = [...emails];
    updatedEmails.splice(index, 1);
    setEmails(updatedEmails);
  };

  const formSubmitted = () => {
    if (!firstSubmit) {
      setFirstSubmit(true);
    }
    const notValidEmails = emails.filter((email) => {
      return !isValidEmail(email);
    });
    const invalidEmailExist = notValidEmails.length > 0;
    if (!invalidEmailExist) {
      console.log("now submitting");
      console.log(emails);
    }
  };

  const valChanged = (e, index) => {
    const updatedEmails = [...emails];
    updatedEmails[index] = e.target.value;
    if (firstSubmit) {
      const isValid = isValidEmail(e.target.value);
      if (isValid) {
        if (invalidArrayIndexes.indexOf(index) > -1) {
          const updatedInvalidArrayIndexes = [...invalidArrayIndexes];
          updatedInvalidArrayIndexes.splice(
            updatedInvalidArrayIndexes.indexOf(index),
            1
          );
          setInvalidArrayIndexes(updatedInvalidArrayIndexes);
        }
      } else {
        if (invalidArrayIndexes.indexOf(index) < 0) {
          const updatedInvalidArrayIndexes = [...invalidArrayIndexes];
          updatedInvalidArrayIndexes.push(index);
          setInvalidArrayIndexes(updatedInvalidArrayIndexes);
        }
      }
    }
    setEmails(updatedEmails);
  };

  const emailList = emails.map((email, index) => {
    return (
      <Form.Item
        key={index}
        name="email"
        label="email"
        rules={[{ required: true, message: "Please enter your email!" }]}
        validateStatus={invalidArrayIndexes.includes(index) && "error"}
        help={invalidArrayIndexes.includes(index) ? "not a valid email" : " "}
      >
        <Input
          style={{ width: 300 }}
          placeholder="enter email"
          value={email}
          onChange={(e) => valChanged(e, index)}
        />
        <Button type="label" onClick={() => removeEmail(index)}>
          remove email
        </Button>
      </Form.Item>
    );
  });

  return (
    <div>
      {emailList}
      <Button type="label" onClick={addEmail}>
        add new email
      </Button>
      <div style={{ marginTop: 20 }}>
        <Button type="primary" onClick={formSubmitted}>
          send emails
        </Button>
      </div>
    </div>
  );
};

export default MyForm;

【问题讨论】:

    标签: arrays reactjs validation antd


    【解决方案1】:

    您看不到所需错误消息的原因是,当您的元素被Form 组件包装并且在提交表单之后,ant design 的验证规则起作用。但是,这并不能解决您的问题,因为这种用法仅支持单个表单项,每个项都具有唯一的name。 我建议您使用 React 表单验证库 react-validatable-form 来验证您的字符串列表,因为它很好地抽象了验证工作流和 DOM 元素绑定的验证结果。首先,您应该使用 ReactValidatableFormProvider 包装您的应用程序,例如:

    import { ReactValidatableFormProvider } from "react-validatable-form";
    import "antd/dist/antd.css";
    import MyForm from "./MyForm";
    
    export default function App() {
      return (
        <ReactValidatableFormProvider>
          <MyForm />
        </ReactValidatableFormProvider>
      );
    }
    

    然后您可以将useValidatableForm 钩子与带有listPath 的规则集一起使用,例如:

    import { Button, Form, Input } from "antd";
    import { useValidatableForm } from "react-validatable-form";
    import get from "lodash.get";
    
    const initialFormData = {
      emails: [""]
    };
    const rules = [
      { listPath: "emails", ruleSet: [{ rule: "required" }, { rule: "email" }] }
    ];
    
    const MyForm = () => {
      const {
        isValid,
        validationError,
        formData,
        setPathValue,
        setFormIsSubmitted
      } = useValidatableForm({
        rules,
        initialFormData,
        hideBeforeSubmit: true
      });
    
      const addEmail = () => {
        const updatedEmails = get(formData, "emails");
        updatedEmails.push("");
        setPathValue("emails", updatedEmails);
      };
    
      const removeEmail = (index) => {
        const updatedEmails = get(formData, "emails");
        updatedEmails.splice(index, 1);
        setPathValue("emails", updatedEmails);
      };
    
      const formSubmitted = () => {
        setFormIsSubmitted();
        if (isValid) {
          console.log("now submitting");
          console.log(get(formData, "emails"));
        }
      };
    
      const emailList = get(formData, "emails").map((email, index) => {
        return (
          <Form.Item
            key={index}
            validateStatus={get(validationError, `emails{${index}}`) && "error"}
            help={get(validationError, `emails{${index}}`) || " "}
          >
            <Input
              style={{ width: 300 }}
              placeholder="enter email"
              value={get(formData, `emails[${index}]`)}
              onChange={(e) => setPathValue(`emails[${index}]`, e.target.value)}
            />
            <Button type="label" onClick={() => removeEmail(index)}>
              remove email
            </Button>
          </Form.Item>
        );
      });
    
      return (
        <div>
          {emailList}
          <Button type="label" onClick={addEmail}>
            add new email
          </Button>
          <div style={{ marginTop: 20 }}>
            <Button type="primary" onClick={formSubmitted}>
              send emails
            </Button>
          </div>
        </div>
      );
    };
    
    export default MyForm;
    

    您可以查看this sandbox 以获取实时工作示例。

    【讨论】:

    • 谢谢,有没有办法用这个表单验证库检查列表中是否存在多个相同的电子邮件?
    • 是的,您可以将unique 规则添加到列表元素中。您还可以将自定义消息设置为特定规则,例如 customMessage: "Please enter your email!"。我创建了another sandbox 来展示这些要求的示例用法。
    【解决方案2】:

    我建议使用类似于 yup 的库。 是的,您可以为表单定义架构,如下所示:

    const RegisterUserValidationSchema = yup.object().shape({
        name: yup.string()
            .min(2, "No way,too short!")
            .max(200, "So long,are you serious?")
            .required("Required"),
        email: yup.string().email("Please enter an email").required("Required"),
        password: yup.string().required("Password is required"),
        confirmPassword: yup.string()
            .oneOf([yup.ref('password'), null], "Passwords must match"),
        phoneNumber: yup.number("Please enter a valid phone number"),
    })
    

    然后,您可以将您的值与您的架构进行比较

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-23
      • 1970-01-01
      • 2015-02-13
      • 2022-12-11
      • 1970-01-01
      • 1970-01-01
      • 2016-06-05
      • 2019-10-16
      相关资源
      最近更新 更多