Formik/Yup 验证中的重复错误

Duplicate Errors on Formik/Yup Validation

我在 Formik 中使用以下验证模式:


    validationSchema = {
      Yup.object({
        emails: Yup.array()
          .of(Yup.string().email('Please enter valid email addresses only.'))
          .min(1, 'At least one email address is required.')
      })
    }

它工作得很好,除了因为我使用的是 Material UI AutoComplete 组件,当用户输入多个无效的电子邮件地址时,他们会看到每个无效的电子邮件地址一次错误消息。

有什么解决办法吗?

这是一个沙盒 link:https://codesandbox.io/s/wild-sea-h2i0m?file=/src/App.tsx

然后您要做的是确保过滤掉重复的错误。您应该确保每条错误消息都是唯一的。我写了一个函数来帮助你做到这一点。

我更新了你的 EmailsField 组件:

import React from "react";
import Autocomplete from "@material-ui/lab/Autocomplete";
import Chip from "@material-ui/core/Chip";
import CloseIcon from "@material-ui/icons/Close";
import TextField from "@material-ui/core/TextField";
import { FieldProps } from "formik";

const isEmailValid = (email: string) =>
  /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

const EmailsField = ({
  field,
  form: { errors, touched, setTouched, setFieldValue },
  ...props
}: FieldProps) => {
  console.log('errors', errors)
  const name = field.name;
  const [value, setValue] = React.useState<string[]>([]);
  const [inputValue, setInputValue] = React.useState("");

  const handleChange = (event: React.ChangeEvent<{}>, emails: string[]) => {
    setTouched({ ...touched, [name]: true });
    setValue(emails);
    event.persist();
    setFieldValue(name, emails);
  };

  const handleInputChange = (
    event: React.ChangeEvent<{}>,
    newInputValue: string
  ) => {
    const options = newInputValue.split(/[ ,]+/);
    const fieldValue = value
      .concat(options)
      .map(x => x.trim())
      .filter(x => x);

    if (options.length > 1) {
      handleChange(event, fieldValue);
    } else {
      setInputValue(newInputValue);
    }
  };

  // 1. This function will help remove duplicated errors
  const getEmailErrors = (errors: any) => {
    return Array.isArray(errors)
      ?  errors.filter((email: string, i: number, arr: any) => arr.indexOf(email) === i)
      : errors;
  }

  return (
    <Autocomplete<string>
      multiple
      disableClearable={true}
      options={[]}
      freeSolo
      renderTags={(emails, getTagProps) =>
        emails.map((email, index) => (
          <Chip
            deleteIcon={<CloseIcon />}
            variant="default"
            label={email}
            color={isEmailValid(email) ? "primary" : "secondary"}
            {...getTagProps({ index })}
          />
        ))
      }
      value={value}
      inputValue={inputValue}
      onChange={handleChange}
      onInputChange={handleInputChange}
      renderInput={params => (
        <TextField
          {...params}
          name={name}
          error={touched[name] && Boolean(errors.emails)}
          //---------------------------------------->>>> Call it here
          helperText={touched[name] && errors.emails && getEmailErrors(errors.emails as any)}
          variant="outlined"
          InputProps={{ ...params.InputProps }}
          {...props}
        />
      )}
    />
  );
};

export default EmailsField;