简体   繁体   English

Formik & yup 表单验证无法按预期使用 VirtualizedSelect

[英]Formik & yup form validation not working as expected with VirtualizedSelect

I created a form with formik in order to have form validations.我用 formik 创建了一个表单,以便进行表单验证。 I have used the components Formik, Form, Field form formik and configured them:我使用了组件 Formik、Form、Field form formik 并配置了它们:

    import { Formik, Form, Field } from "formik";
    import { object, string } from "yup";
    import isEmpty from "lodash/isEmpty";
    import FormikSelectInput from "../common/FormikSelectInput";

    class App extends Component {
      render() {
        const options = this.props.categories.map(c => {
          return { label: c.name, value: c.name };
        });

        return (
          <Formik
            validationSchema={object().shape({
              category: string().required("Category is required.")
            })}
            initialValues={this.props.obj}
            onSubmit={(values, actions) => {
              console.log(values);
            }}
            render={({ errors, dirty, isSubmitting, setFieldValue }) => (
              <Form>
                <Field
                  name="category"
                  label="Categories"
                  value={this.props.obj.category.name}
                  options={options}
                  component={FormikSelectInput}
                />
                <button
                  type="submit"
                  className="btn btn-default"
                  disabled={isSubmitting || !isEmpty(errors) || !dirty}
                >
                  Save
                </button>
              </Form>
            )}
          />
        );
      }
    }

    //Prop Types validation
    App.propTypes = {
      obj: PropTypes.object.isRequired,
      categories: PropTypes.array.isRequired,
      actions: PropTypes.object.isRequired
    };
    const getElementByID = (items, id) => {
  let res = items.filter(l => l.id === id);
  return res.length ? res[0] : null; //since filter returns an array we need to check for res.length
};
    //Redux connect
    const mapStateToProps = ({ objects, categories }, ownProps) => {
      let obj = {
        id: "",
        name: "",
        category: { id: "", name: "" }
      };
      return {
        obj: getElementByID(objects, ownProps.match.params.id) || obj,
        categories: categories
      };
    };

    export default connect(
      mapStateToProps,
      {...}
    )(App);

And I have a custom component 'FormikSelectInput':我有一个自定义组件“FormikSelectInput”:

import React, { Component } from "react";
import classnames from "classnames";
import VirtualizedSelect from "react-virtualized-select";
import "react-select/dist/react-select.css";
import "react-virtualized/styles.css";
import "react-virtualized-select/styles.css";

const InputFeedback = ({ children }) => (
  <span className="text-danger">{children}</span>
);

const Label = ({ error, children, ...props }) => {
  return <label {...props}>{children}</label>;
};

class FormikSelectInput extends Component {
  constructor(props) {
    super(props);
    this.state = { selectValue: this.props.value };
  }

  render() {
    const {
      field: { name, ...field }, // { name, value, onChange, onBlur }
      form: { touched, errors }, // also values, setXXXX, handleXXXX, dirty, isValid, status, etc.
      className,
      label,
      ...props
    } = this.props;

    const error = errors[name];
    const touch = touched[name];
    const classes = classnames(
      "form-group",
      {
        "animated shake error": !!error
      },
      className
    );

    console.log("props", props);
    return (
      <div className={classes}>
        <Label htmlFor={name} error={error}>
          {label}
        </Label>
<VirtualizedSelect
          name={name}
          id={name}
          className="form-control"
          {...field}
          {...props}
          onChange={(selectValue) => this.setState(() => {
            this.props.form.setFieldValue('category',selectValue)
            return { selectValue } 
          })}
          value={this.state.selectValue}
        /> 
        {touch && error && <InputFeedback>{error}</InputFeedback>}
      </div>
    );
  }
}

export default FormikSelectInput;

My component is working and I am able to select an option, but why formik together with 'yup' validation showing me an error when I empty the select field.我的组件正在工作,我能够 select 一个选项,但是当我清空 select 字段时,为什么 formik 和 'yup' 验证向我显示错误。

When I clear my select field I get an ERROR - 'category must be a string type, but the final value was: null .当我清除 select 字段时,出现错误 - 'category must be a string type, but the final value was: null If "null" is intended as an empty value be sure to mark the schema as .nullable() '如果“null”意为空值,请务必将模式标记为.nullable() '

在此处输入图像描述

My code is based on the this example .我的代码基于这个例子

It looks like the field is expecting the string to be required based on your validationSchema .看起来该字段期望根据您的validationSchema需要该字符串。

The error helped point me in the right direction.该错误帮助我指明了正确的方向。 Here's the docs for Yup .nullable() : https://github.com/jquense/yup#mixednullableisnullable-boolean--true-schema这是.nullable()的文档: https : //github.com/jquense/yup#mixednullableisnullable-boolean--true-schema

Try adding .nullable() to the chain of validations.尝试将 .nullable() 添加到验证链中。

validationSchema={object().shape({ category: string().required("Category is required.").nullable() })}

Hope this helps.希望这可以帮助。 在此处输入图片说明

Don't assign default value (initialValue in formik) as null.不要将默认值(formik 中的 initialValue)分配为 null。

I have also had same problem like I was using initial values as this way我也有同样的问题,就像我这样使用初始值一样

const initValues = {
name : data?.name
}

so, my problem was till the data?.name was defined every thing was fine but since the data?.name was null then it is assigned null to the initValues of formik but in yup I haven't assign it to be null so I did it like所以,我的问题是直到定义了数据?.name 一切都很好但是因为数据?.name 是 null 然后它被分配给 null 到 formik 的 initValues 但在是的我没有分配它是 null 所以我喜欢吗

const initValues = {
name : data?.name || ""
}

It checks either data?.name is null if null then it will assign them to ''.So it wont be nullable它检查任一数据?名称为 null 如果 null 则它将它们分配给“”。因此它不会为空

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM