javascript - 使用 Formik 编辑条目,Yup 无法识别现有字段

标签 javascript reactjs validation formik yup

我正在使用 FormikYup当我创建一个实体(在本例中为公司)以检查字段是否正确并且所有这些都被引入(都是必需的)时。
当我创建一个实体时它工作正常:它只允许您在引入所有字段并且满足规则时创建它(目前只有一个规则用于电子邮件)。
这是用于创建具有 2 个字段名称和电子邮件的新公司的代码:

    import React from 'react';
    import { Redirect } from 'react-router-dom';
    import { Formik, Form, Field } from 'formik';
    import { Input, Button, Label, Grid } from 'semantic-ui-react';
    import { connect } from 'react-redux';
    import * as Yup from 'yup';
    import { Creators } from '../../../actions';
    import Layout from '../../Layout/Layout';
    
    class CreateCompanyForm extends React.PureComponent {
      constructor(props) {
        super(props);
    
        this.state = {
          name: '',
          contactMail: '',
          redirectCreate: false,
          redirectEdit: false,
          edit: false,
        };
      }
    
      componentDidMount() {
        const {
          getCompany,
          location: { pathname },
        } = this.props;
      }
    
      handleSubmit = values => {
        const { createCompany, getCompanies } = this.props;
        createCompany(values);
        this.setState({ redirectCreate: true });
        getCompanies(this.props.query);
      };
    
      render() {
        let title = 'Create Company';
        let buttonName = 'Create';
        let submit = this.handleSubmitCreate;
    
        const { redirectCreate, redirectEdit } = this.state;
    
        if (redirectCreate) {
          return <Redirect to="/companies" />;
        }
        const initialValues = {
          name: '',
          contactMail: '',
        };
        const requiredErrorMessage = 'This field is required';
        const emailErrorMessage = 'Please enter a valid email address';
        const validationSchema = Yup.object({
          name: Yup.string().required(requiredErrorMessage),
          contactMail: Yup.string()
            .email(emailErrorMessage)
            .required(requiredErrorMessage),
        });
        return (
          <Layout>
            <div>
              <Button type="submit" form="amazing">
                Create company
              </Button>
              <Button onClick={() => this.props.history.goBack()}>Discard</Button>
              <div>Create company</div>
            </div>
    
            <Formik
              htmlFor="amazing"
              initialValues={initialValues}
              validationSchema={validationSchema}
              onSubmit={values => this.handleSubmit(values)}>
              {({ values, errors, touched, setValues }) => (
                <Form id="amazing">
                  <Grid columns={2}>
                    <Grid.Column>
                      <Label>Company Name</Label>
                      <Field name="name" as={Input} placeholder="Hello" />
                      <div>{touched.name && errors.name ? errors.name : null}</div>
                    </Grid.Column>
    
                    <Grid.Column>
                      <Label>Contact Mail</Label>
                      <Field
                        name="contactMail"
                        as={Input}
                        placeholder="johnappleseed@hello.com"
                      />
                      <div>
                        {touched.contactMail && errors.contactMail
                          ? errors.contactMail
                          : null}
                      </div>
                    </Grid.Column>
                  </Grid>
                </Form>
              )}
            </Formik>
          </Layout>
        );
      }
    }
    
    const mapStateToProps = state => ({
      companies: state.companies.companies,
      company: state.companies.selectedCompany,
      query: state.companies.query,
    });
    
    const mapDispatchToProps = {
      getCompanies: Creators.getCompaniesRequest,
      createCompany: Creators.createCompanyRequest,
      getCompany: Creators.getCompanyRequest,
      updateCompany: Creators.updateCompanyRequest,
    };

export default connect(mapStateToProps, mapDispatchToProps)(CreateCompanyForm);

当我想编辑公司时出现问题。因此,当有人在编辑按钮上单击公司时,它应该打开公司,其所有字段都包含应可编辑的当前值。
为了获取我使用状态的那些当前值,例如可以从 this.state.email 访问电子邮件并且为了改变它被添加的值onChange方法。
可以在文本输入中修改这些值。但是,它会触发 Yup 消息,指出该字段是必需的,即使其中有数据 - 为什么会发生这种情况?该字段不为空,这是它必须显示该消息的情况。
当然,当我单击保存实体时它不会更新实体,因为它需要这些字段。
这是代码:
import React from 'react';
...

class CreateCompanyForm extends React.PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      name: '',
      contactMail: '',
      redirectCreate: false,
      redirectEdit: false,
      edit: false,
    };
  }

  componentDidMount() {
    const {
      getCompany,
      location: { pathname },
    } = this.props;
    if (pathname.substring(11) !== 'create') { // checks the URL if it is in edit mode 
      getCompany(pathname.substring(16));
      this.setState({
        edit: true,
      });
      this.setState({
        name: this.props.company.name,
        contactMail: this.props.company.contactMail,
      });
    }
  }

    onChange = (e, { name, value }) => { // method to update the state with modified value in input
      this.setState({ [name]: value });
    };

  handleSubmit = values => {
    const { createCompany, getCompanies } = this.props;
    createCompany(values);
    this.setState({ redirectCreate: true });
    getCompanies(this.props.query);
  };

    handleSubmitEdit = e => {
      e.preventDefault();
      const { name, contactMail } = this.state;
      const { updateCompany } = this.props;
      updateCompany(this.props.company._id, {
        name,
        contactMail,
      });
      this.setState({ redirectEdit: true });
    };

  render() {
    let title = 'Create Company';
    let buttonName = 'Create';
    let submit = this.handleSubmitCreate;

    const { redirectCreate, redirectEdit } = this.state;

    if (redirectCreate) {
      return <Redirect to="/companies" />;
    }

    if (redirectEdit) {
      return <Redirect to={`/companies/${this.props.company._id}`} />;
    }

    if (this.state.edit) {
      title = 'Edit Company';
      buttonName = 'Edit';
      submit = this.handleSubmitEdit;
    }

    const initialValues = {
      name: '',
      contactMail: '',
    };
    const requiredErrorMessage = 'This field is required';
    const emailErrorMessage = 'Please enter a valid email address';
    const validationSchema = Yup.object({
      name: Yup.string().required(requiredErrorMessage),
      contactMail: Yup.string()
        .email(emailErrorMessage)
        .required(requiredErrorMessage),
    });
    return (
      <Layout>
        <div>
          <Button type="submit" form="amazing">
            Create company
          </Button>
          <Button onClick={() => this.props.history.goBack()}>Discard</Button>
          <div>Create company</div>
        </div>

        <Formik
          htmlFor="amazing"
          initialValues={initialValues}
          validationSchema={validationSchema}
          onSubmit={values => this.handleSubmit(values)}>
          {({ values, errors, touched, setValues }) => (
            <Form id="amazing">
              <Grid columns={2}>
                <Grid.Column>
                  <Label>Company Name</Label>
                  <Field
                    name="name"
                    as={Input}
                    placeholder="Hello"
                    value={this.state.name || ''} // takes the value from the state
                    onChange={this.onChange} // does the changing 
                  />
                  <div>{touched.name && errors.name ? errors.name : null}</div>
                </Grid.Column>

                <Grid.Column>
                  <Label>Contact Mail</Label>
                  <Field
                    name="contactMail"
                    as={Input}
                    placeholder="johnappleseed@hello.com"
                    value={this.state.contactMail || ''} // takes the value from the state
                    onChange={this.contactMail} // does the changing 
                  />
                  <div>
                    {touched.contactMail && errors.contactMail
                      ? errors.contactMail
                      : null}
                  </div>
                </Grid.Column>
              </Grid>
            </Form>
          )}
        </Formik>
      </Layout>
    );
  }
}

...

export default connect(mapStateToProps, mapDispatchToProps)(CreateCompanyForm);
有关如何解决此问题并使字段可编辑并删除 'This field is required' 的任何想法字段已经有数据时的消息?

最佳答案

您需要做 3 个小改动:
1.您的初始值始终设置为:

const initialValues = {
   name: '',
   contactMail: '',
};
您需要将其更改为:
const initialValues = {
   name: this.state.name,
   contactMail: this.state.contactMail,
};
2. 添加enableReinitializeFormik
即使更改为 1,您的提交仍然会抛出错误,这是因为在创建组件时,Formik使用构造函数中的值呈现:
this.state = {
      name: "",
      contactMail: "",
      redirectCreate: false,
      redirectEdit: false,
      edit: false,
    };
当你在 componentDidMount 内部改变状态时, Formik不使用更新值重新初始化:
componentDidMount() {
    const {
      getCompany,
      location: { pathname },
    } = this.props;
    if (pathname.substring(11) !== 'create') { // checks the URL if it is in edit mode 
      getCompany(pathname.substring(16));
      this.setState({
        edit: true,
      });
      this.setState({
        name: this.props.company.name,
        contactMail: this.props.company.contactMail,
      });
    }
  }
因此,要重新初始化 formik,您需要添加 enableReinitialize给它,像这样:
  <Formik
     htmlFor="amazing"
     /// HERE'S THE CODE
     enableReinitialize
     initialValues={initialValues}
     ....
3. 与enableReinitialize , Formik将在 Blur 和 Change 上触发验证。为避免这种情况,您可以添加 validateOnChangevalidateOnBlur为假:
 <Formik
   htmlFor="amazing"
   enableReinitialize
   validateOnChange={false}
   validateOnBlur={false}
   initialValues={initialValues}
   .....

关于javascript - 使用 Formik 编辑条目,Yup 无法识别现有字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63525393/

相关文章:

javascript - HTML 字段类型 仅输入数字或仅输入字母,无需 JavaScript

javascript - 通过范围输入隐藏 div block jQuery

javascript - Webpack require.ensure(code splitting) 与 react 组件不工作?

ASP.NET MVC 3 : programmatically add DataAnnotation (RequiredAttribute) to view model

javascript - 匹配字符串中至少 1 个数字和 1 个字符的正则表达式模式

javascript - 如何在一个数组中获取某些部分并将它们转换为javascript中的另一个字符

javascript - 如何使用javascript回到网站底部,如回到顶部?

javascript - 选择器不会在react-native-elements中渲染

reactjs - 如何强制 react native 内容忽略键盘?

asp.net - 如何验证列表框不为空(客户端)