Formik使用详解

Formik使用详解

react-formik

1 引言

formik

在现代Web应用程序中,表单是一种不可避免的输入机制,但是处理表单的过程可能会变得非常复杂。Formik是一个React表单库,它的目标是简化表单处理的过程。本文将介绍Formik的主要功能和用途,以及如何使用它来简化React表单的处理。

1.1 介绍Formik

Formik是一个专为React构建的开源表单库。它提供了一个易于使用的API来处理表单状态管理,表单验证以及表单提交。Formik支持React中的所有表单元素和事件,可以很好地与React生态系统中的其他库集成。同时,Formik还提供了一些高级功能,如支持异步验证、字段级别的验证、根据表单状态变化自动计算计算属性等。

1.2 本文目的

本文的目的是介绍如何使用Formik来处理React中的表单,包括如何管理表单状态、如何进行表单验证、如何处理表单提交等。本文还将介绍Formik的高级功能和最佳实践,以及与React生态系统中其他库的集成方法。通过本文,读者将能够理解Formik的使用方法,从而更好地管理React中的表单。

2 Formik基础知识介绍

form

2.1 表单处理

在Web应用程序开发中,表单处理是必不可少的一部分。Formik是一个用于React应用程序的表单处理库,它可以帮助开发者轻松地处理复杂的表单,提高表单的可维护性和可重用性。

2.2 Formik的优势

相较于传统的表单处理方法,Formik具有以下优势:

  1. 状态管理: Formik自动地处理表单状态管理,无需手动编写大量的状态管理逻辑。
  2. 表单验证: Formik提供了易于使用的表单验证工具,可以快速实现表单验证逻辑。
  3. 表单提交: Formik可以方便地处理表单提交,包括异步表单提交和重试机制。
  4. 支持复杂表单: Formik支持处理包括多级嵌套、动态表单、数组表单等多种复杂表单。

3 安装和设置Formik

在本节中,我们将介绍如何安装和设置Formik,并且创建一个简单的表单来演示Formik的基本用法。此外,我们还将探讨Formik的高级特性。
formik

3.1 安装Formik

要使用Formik,我们需要先安装它。我们可以使用npm或yarn安装Formik。在终端中,切换到你的项目目录并运行以下命令:

npm install formik

yarn add formik

这将安装最新版本的Formik包。

3.2 创建表单

接下来,我们将创建一个简单的表单来演示如何使用Formik。我们的表单将有两个字段:一个文本框和一个提交按钮。当用户在文本框中输入一些文本并单击提交按钮时,我们将在控制台上打印输入的值。

为了创建表单,我们需要在我们的React组件中导入Formik和相关组件。然后,我们需要使用Formik组件包装我们的表单元素。Formik组件有一个名为handleSubmit的函数,它在表单提交时被调用。我们可以在这个函数中执行一些操作,例如打印表单数据。
以下是示例代码:

import React from 'react';
import { Formik, Form, Field } from 'formik';

const BasicForm = () => (
  <Formik
    initialValues={{ text: '' }}
    onSubmit={(values) => {
      console.log(values.text);
    }}
  >
    {({ handleSubmit }) => (
      <Form onSubmit={handleSubmit}>
        <Field name="text" />
        <button type="submit">Submit</button>
      </Form>
    )}
  </Formik>
);

export default BasicForm;

在上面的代码中,我们使用了Formik组件,并传入了一些参数,例如initialValuesonSubmitinitialValues表示我们的表单的初始值,而onSubmit是一个回调函数,它在表单提交时被调用。

我们使用Field组件创建了一个文本框,然后使用button元素创建了一个提交按钮。当用户单击提交按钮时,我们将打印文本框中的值。

3.3 使用Formik的高级特性

Formik具有许多高级特性,例如表单验证和嵌套字段。下面是一个演示如何使用这些特性的示例代码:

import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

// 定义内部嵌套表单的初始值
const initialValues = {
  name: '',
  email: '',
  phone: '',
  address: {
    street: '',
    city: '',
    state: '',
    zip: ''
  }
};

// 使用Yup定义表单验证规则
const validationSchema = Yup.object({
  name: Yup.string().required('姓名不能为空'),
  email: Yup.string().email('无效的电子邮件地址').required('电子邮件地址不能为空'),
  phone: Yup.string().matches(/^\d{10}$/, '无效的电话号码').required('电话号码不能为空'),
  address: Yup.object({
    street: Yup.string().required('街道不能为空'),
    city: Yup.string().required('城市不能为空'),
    state: Yup.string().required('州不能为空'),
    zip: Yup.string().matches(/^\d{5}$/, '无效的邮政编码').required('邮政编码不能为空')
  })
});

// 渲染表单组件
const SignupForm = () => (
  <Formik
    initialValues={initialValues}
    validationSchema={validationSchema}
    onSubmit={(values, { setSubmitting }) => {
      setTimeout(() => {
        alert(JSON.stringify(values, null, 2));
        setSubmitting(false);
      }, 400);
    }}
  >
    {({ isSubmitting }) => (
      <Form>
        <div>
          <label htmlFor="name">姓名</label>
          <Field type="text" name="name" />
          <ErrorMessage name="name" />
        </div>

        <div>
          <label htmlFor="email">电子邮件</label>
          <Field type="email" name="email" />
          <ErrorMessage name="email" />
        </div>

        <div>
          <label htmlFor="phone">电话号码</label>
          <Field type="tel" name="phone" />
          <ErrorMessage name="phone" />
        </div>

        <div>
          <h3>地址</h3>

          <div>
            <label htmlFor="address.street">街道</label>
            <Field type="text" name="address.street" />
            <ErrorMessage name="address.street" />
          </div>

          <div>
            <label htmlFor="address.city">城市</label>
            <Field type="text" name="address.city" />
            <ErrorMessage name="address.city" />
          </div>

          <div>
            <label htmlFor="address.state"></label>
            <Field type="text" name="address.state" />
            <ErrorMessage name="address.state" />
          </div>

          <div>
            <label htmlFor="address.zip">邮政编码</label>
            <Field type="text" name="address.zip" />
            <ErrorMessage name="address.zip" />
          </div>
        </div>

        <button type="submit" disabled={isSubmitting}>
          提交
        </button>
      </Form>
    )}
  </Formik>
);

export default SignupForm;

这个示例代码展示了如何使用Yup定义表单验证规则,并使用Formik处理表单的嵌套字段。

4 Formik的核心功能

Formik 为表单处理提供了一组核心功能,包括值管理、表单提交、表单重置以及处理验证和错误。在这一部分,我们将深入探讨这些功能。
formik

4.1 值管理

Formik 提供了一种简单的方式来管理表单中的值。通过 values 属性,我们可以访问表单中所有输入框的值。这个属性的值是一个对象,每个属性对应一个输入框的值。例如:

import { Formik } from 'formik';

function MyForm() {
  return (
    <Formik
      initialValues={{ firstName: '', lastName: '', email: '' }}
      onSubmit={(values) => {
        console.log(values);
      }}
    >
      {({ values, handleChange }) => (
        <form>
          <input name="firstName" value={values.firstName} onChange={handleChange} />
          <input name="lastName" value={values.lastName} onChange={handleChange} />
          <input name="email" value={values.email} onChange={handleChange} />
        </form>
      )}
    </Formik>
  );
}

在这个例子中,我们定义了一个包含三个输入框的表单。initialValues 属性定义了这些输入框的初始值。在 onSubmit 回调函数中,我们可以访问表单中所有输入框的值。在表单的渲染函数中,我们可以通过 valueshandleChange 属性访问和管理这些值。

4.2 表单提交

Formik 提供了一种简单的方式来处理表单的提交。通过 onSubmit 属性,我们可以定义一个回调函数,该函数在表单提交时被调用。例如:

import { Formik } from 'formik';

function MyForm() {
  return (
    <Formik
      initialValues={{ firstName: '', lastName: '', email: '' }}
      onSubmit={(values, { setSubmitting }) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          setSubmitting(false);
        }, 400);
      }}
    >
      {({ values, handleChange, handleSubmit, isSubmitting }) => (
        <form onSubmit={handleSubmit}>
          <input name="firstName" value={values.firstName} onChange={handleChange} />
          <input name="lastName" value={values.lastName} onChange={handleChange} />
          <input name="email" value={values.email} onChange={handleChange} />
          <button type="submit" disabled={isSubmitting}>
            Submit
          </button>
        </form>
      )}
    </Formik>
  );
}

在这个例子中,我们定义了一个包含三个输入框和一个提交按钮的表单。通过 onSubmit 属性,我们定义了一个回调函数,在表单提交时被调用。在回调函数中,我们可以访问表单中所有输入框的值,并执行提交操作。通过 setSubmitting 函数,我们可以设置表单的提交状态。

在表单的渲染函数中,我们通过 handleSubmit 属性来处理表单的提交。我们还使用isSubmitting属性来禁用提交按钮,直到表单提交完成。

4.3 表单重置

Formik表单重置的功能非常有用,可以让用户在重新填写表单时方便地重置表单。重置表单后,表单将恢复到其初始状态,所有字段的值都将被清除。

为了实现这个功能,我们可以在Formik的表单中使用resetForm函数。该函数可以将表单重置为其初始值,并清除任何错误消息和提交状态。我们可以将resetForm函数传递给一个按钮或链接,以便在用户单击该按钮或链接时触发表单重置。

以下是一个示例代码,演示如何在React组件中使用Formik的resetForm函数来重置表单:

import React from 'react';
import { Formik, Field, Form, ErrorMessage } from 'formik';
import * as Yup from 'yup';

const SignupForm = () => {
  return (
    <Formik
      initialValues={{
        firstName: '',
        lastName: '',
        email: '',
      }}
      validationSchema={Yup.object().shape({
        firstName: Yup.string()
          .max(15, 'Must be 15 characters or less')
          .required('Required'),
        lastName: Yup.string()
          .max(20, 'Must be 20 characters or less')
          .required('Required'),
        email: Yup.string()
          .email('Invalid email address')
          .required('Required'),
      })}
      onSubmit={(values, { setSubmitting }) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          setSubmitting(false);
        }, 400);
      }}
    >
      {({ isSubmitting, resetForm }) => (
        <Form>
          <label htmlFor="firstName">First Name</label>
          <Field type="text" name="firstName" />
          <ErrorMessage name="firstName" />

          <label htmlFor="lastName">Last Name</label>
          <Field type="text" name="lastName" />
          <ErrorMessage name="lastName" />

          <label htmlFor="email">Email Address</label>
          <Field type="email" name="email" />
          <ErrorMessage name="email" />

          <button type="submit" disabled={isSubmitting}>
            Submit
          </button>
          <button type="button" onClick={resetForm}>
            Reset
          </button>
        </Form>
      )}
    </Formik>
  );
};

export default SignupForm;

在上面的代码中,我们定义了一个SignupForm组件,它使用了FormikYup库来实现表单验证和处理。表单中有三个字段:firstName、lastName和email。我们还定义了一个按钮来触发表单提交,以及一个按钮来重置表单。当用户单击重置按钮时,resetForm函数将被调用,表单将被重置为其初始值。

通过这种方式,我们可以轻松地实现Formik表单的重置功能,让用户在重新填写表单时更加便捷。

4.4 动态表单

动态表单是指表单中的字段可以根据用户的输入或其他条件而动态变化。这种情况下,我们需要动态地添加或删除表单字段,并根据用户的输入进行验证。

Formik提供了FieldArray组件来实现动态表单。我们可以通过FieldArrayname属性来指定一个数组类型的表单字段,然后通过render属性来指定如何渲染每个元素。例如,下面的代码实现了一个可以动态添加或删除电子邮件地址的表单:

import { Formik, Form, FieldArray, ErrorMessage } from 'formik';

function DynamicForm() {
  return (
    <Formik
      initialValues={{ emails: [''] }}
      onSubmit={(values, actions) => {
        alert(JSON.stringify(values, null, 2));
        actions.setSubmitting(false);
      }}
    >
      {({ values }) => (
        <Form>
          <FieldArray name="emails">
            {({ remove, push }) => (
              <div>
                {values.emails.map((email, index) => (
                  <div key={index}>
                    <input
                      type="email"
                      name={`emails.${index}`}
                      value={email}
                      onChange={(event) => {
                        const newEmails = [...values.emails];
                        newEmails[index] = event.target.value;
                        push(newEmails);
                      }}
                    />
                    <button type="button" onClick={() => remove(index)}>
                      删除
                    </button>
                  </div>
                ))}
                <button type="button" onClick={() => push('')}>
                  添加电子邮件地址
                </button>
              </div>
            )}
          </FieldArray>
          <button type="submit">提交</button>
        </Form>
      )}
    </Formik>
  );
}

在上面的代码中,我们使用了FieldArray组件来处理动态表单。FieldArray组件的name属性指定了一个数组类型的表单字段emails,然后通过render属性来指定如何渲染每个元素。在每个元素的渲染中,我们将表单的值和控件的事件处理函数绑定在一起,这样当用户输入时,Formik会自动更新表单的值和验证状态。

4.5 嵌套表单

Formik支持嵌套表单,可以在表单中使用另一个表单。这种方法可以很好地组织和处理复杂的表单数据。

要在Formik中使用嵌套表单,我们需要使用FieldArray组件,它可以很方便地处理数组字段。我们可以使用FieldArray组件来处理重复的表单元素,例如多个电子邮件地址或电话号码。

下面是一个使用FieldArray组件的示例代码,它显示了如何使用嵌套表单处理联系人列表:

import React from 'react';
import { Formik, Form, Field, FieldArray } from 'formik';
import * as Yup from 'yup';

const ContactFormSchema = Yup.object().shape({
  contacts: Yup.array().of(
    Yup.object().shape({
      name: Yup.string().required('Name is required'),
      email: Yup.string().email('Invalid email').required('Email is required'),
      phone: Yup.string().required('Phone is required'),
    })
  ),
});

const initialValues = {
  contacts: [
    {
      name: '',
      email: '',
      phone: '',
    },
  ],
};

const ContactForm = () => {
  return (
    <Formik
      initialValues={initialValues}
      validationSchema={ContactFormSchema}
      onSubmit={(values) => console.log(values)}
    >
      {({ values }) => (
        <Form>
          <FieldArray name="contacts">
            {({ push, remove }) => (
              <div>
                {values.contacts.map((contact, index) => (
                  <div key={index}>
                    <Field name={`contacts[${index}].name`} />
                    <Field name={`contacts[${index}].email`} />
                    <Field name={`contacts[${index}].phone`} />
                    <button type="button" onClick={() => remove(index)}>
                      Remove
                    </button>
                  </div>
                ))}
                <button type="button" onClick={() => push({ name: '', email: '', phone: '' })}>
                  Add Contact
                </button>
              </div>
            )}
          </FieldArray>
          <button type="submit">Submit</button>
        </Form>
      )}
    </Formik>
  );
};

export default ContactForm;

在上面的代码中,我们使用FieldArray组件来处理名为“contacts”的数组字段。在render函数中,我们可以使用map()方法来遍历数组,并为每个数组元素创建一个表单。此外,我们还可以使用push()方法来添加一个新的空白联系人表单,使用remove()方法删除一个联系人表单。

需要注意的是,我们在嵌套表单中使用了嵌套命名,例如contacts[${index}].name,以确保表单数据正确地映射到values对象中。

这个示例演示了如何使用FieldArray组件和嵌套命名来处理嵌套表单。这个方法可以让我们轻松地处理复杂的表单数据,并在表单中使用其他组件。

4.6 处理验证和错误

在实际的应用中,表单的验证和错误处理是很重要的。Formik 提供了非常方便的验证机制,并且还能轻松处理错误消息。

处理验证

Formik 提供了一个 validate 属性,它是一个函数,用于验证表单的值。这个函数会在表单值改变时自动调用。

import { Formik } from 'formik';

const validate = values => {
  const errors = {};
  if (!values.email) {
    errors.email = 'Required';
  } else if (
    !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
  ) {
    errors.email = 'Invalid email address';
  }
  return errors;
};

const SignupForm = () => (
  <Formik
    initialValues={{ email: '', password: '' }}
    validate={validate}
    onSubmit={(values, { setSubmitting }) => {
      setTimeout(() => {
        alert(JSON.stringify(values, null, 2));
        setSubmitting(false);
      }, 400);
    }}
  >
    {({
      values,
      errors,
      touched,
      handleChange,
      handleBlur,
      handleSubmit,
      isSubmitting,
      /* and other goodies */
    }) => (
      <form onSubmit={handleSubmit}>
        <input
          type="email"
          name="email"
          onChange={handleChange}
          onBlur={handleBlur}
          value={values.email}
        />
        {errors.email && touched.email && errors.email}
        <input
          type="password"
          name="password"
          onChange={handleChange}
          onBlur={handleBlur}
          value={values.password}
        />
        {errors.password && touched.password && errors.password}
        <button type="submit" disabled={isSubmitting}>
          Submit
        </button>
      </form>
    )}
  </Formik>
);

在上面的代码中,我们定义了一个 validate 函数来验证表单的值。如果表单值不符合要求,就返回一个错误对象。Formik 会在表单值改变时自动调用这个函数,根据返回的错误对象显示错误消息。

错误处理
当表单提交失败时,我们可以使用 setStatussetErrors 函数来处理错误。setStatus 函数用于设置表单提交的状态,比如正在提交、提交成功或提交失败等。setErrors 函数用于设置表单中的错误消息。

import { Formik } from 'formik';

const SignupForm = () => (
  <Formik
    initialValues={{ email: '', password: '' }}
    validate={(values) => {
      const errors = {};
      if (!values.email) {
        errors.email = 'Required';
      } else if (
        !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
      ) {
        errors.email = 'Invalid email address';
      }
      return errors;
    }}
    onSubmit={(values, { setSubmitting, setStatus, setErrors }) => {
      axios.post('/api/signup', values)
        .then(response => {
          setSubmitting(false);
          setStatus(response.data.message);
        })
        .catch(error => {
          setSubmitting(false);
          setErrors(error.response.data.errors);
       }}

更复杂高级的form验证代码

import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';

function SignupForm() {
  const initialValues = {
    firstName: '',
    lastName: '',
    email: '',
    password: '',
    confirmPassword: '',
    acceptTerms: false
  };

  const validate = (values) => {
    const errors = {};

    if (!values.firstName) {
      errors.firstName = 'Required';
    }

    if (!values.lastName) {
      errors.lastName = 'Required';
    }

    if (!values.email) {
      errors.email = 'Required';
    } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
      errors.email = 'Invalid email address';
    }

    if (!values.password) {
      errors.password = 'Required';
    } else if (values.password.length < 8) {
      errors.password = 'Password must be at least 8 characters long';
    }

    if (values.password !== values.confirmPassword) {
      errors.confirmPassword = 'Passwords do not match';
    }

    if (!values.acceptTerms) {
      errors.acceptTerms = 'Required';
    }

    return errors;
  };

  const handleSubmit = (values, { setSubmitting }) => {
    setTimeout(() => {
      alert(JSON.stringify(values, null, 2));
      setSubmitting(false);
    }, 400);
  };

  return (
    <Formik initialValues={initialValues} validate={validate} onSubmit={handleSubmit}>
      {({ isSubmitting }) => (
        <Form>
          <div>
            <label htmlFor="firstName">First Name</label>
            <Field type="text" name="firstName" />
            <ErrorMessage name="firstName" component="div" className="error-message" />
          </div>

          <div>
            <label htmlFor="lastName">Last Name</label>
            <Field type="text" name="lastName" />
            <ErrorMessage name="lastName" component="div" className="error-message" />
          </div>

          <div>
            <label htmlFor="email">Email</label>
            <Field type="email" name="email" />
            <ErrorMessage name="email" component="div" className="error-message" />
          </div>

          <div>
            <label htmlFor="password">Password</label>
            <Field type="password" name="password" />
            <ErrorMessage name="password" component="div" className="error-message" />
          </div>

          <div>
            <label htmlFor="confirmPassword">Confirm Password</label>
            <Field type="password" name="confirmPassword" />
            <ErrorMessage name="confirmPassword" component="div" className="error-message" />
          </div>

          <div>
            <Field type="checkbox" name="acceptTerms" />
            <label htmlFor="acceptTerms">I accept the terms and conditions</label>
            <ErrorMessage name="acceptTerms" component="div" className="error-message" />
          </div>

          <button type="submit" disabled={isSubmitting}>Submit</button>
        </Form>
      )}
    </Formik>
  );
}

export default SignupForm;

在React应用中,Formik是一个非常强大的表单处理库,可以方便地管理表单的状态,验证表单的输入并处理表单的提交。在本文中,我们将介绍Formik的基础知识、安装和设置、核心功能以及高级特性,并提供详细的示例代码。

5 使用Yup进行表单验证

在前面的部分中,我们已经介绍了如何使用Formik进行表单处理。现在,我们将介绍如何使用Yup来验证表单。
formik

5.1 什么是Yup?

Yup是一个轻量级的JavaScript模式验证库,它允许您定义强大的模式,并且易于使用。它可以与任何JavaScript库一起使用,包括React和Formik。

使用Yup,您可以轻松地定义表单字段应满足的要求,例如必填字段、最小/最大值、字符串格式、日期格式等等。

5.2 在Formik中使用Yup

在Formik中使用Yup非常容易。首先,您需要安装Yup:

npm install yup

然后,您需要导入Yup并定义一个模式。下面是一个简单的模式,用于验证电子邮件地址:

import * as Yup from 'yup';

const SignupSchema = Yup.object().shape({
  email: Yup.string().email('Invalid email').required('Required'),
});

在这个模式中,我们定义了一个名为SignupSchema的对象,它具有一个名为email的字符串属性。我们使用Yup.string()方法定义了字符串属性,然后使用Yup.email()方法验证电子邮件格式是否正确,并使用Yup.required()方法验证该字段是否为必填字段。

要在Formik中使用这个模式,只需将其传递给initialValuesvalidationSchema props即可:

<Formik
  initialValues={{ email: '' }}
  validationSchema={SignupSchema}
  onSubmit={(values, actions) => {
    // 处理提交
  }}
>
  {({ errors, touched, handleSubmit, handleChange, values }) => (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        name="email"
        value={values.email}
        onChange={handleChange}
      />
      {errors.email && touched.email && <div>{errors.email}</div>}
      <button type="submit">Submit</button>
    </form>
  )}
</Formik>

在这个示例中,我们将SignupSchema传递给validationSchema props,并使用Yup.object().shape()方法来定义模式。我们还使用initialValues props将email设置为空字符串。在表单中,我们使用Yup.string()Yup.required()方法来验证电子邮件地址,并在需要时显示错误消息。

6 处理复杂的表单需求

在实际开发中,我们经常会遇到需要处理复杂表单需求的情况,比如包含表单数组或动态添加和删除表单域等。Formik提供了一些方便的方法来处理这些需求。
formik

6.1 使用表单数组

表单数组是指表单中包含多个相同的域,例如多个输入框、复选框或下拉列表等。对于这种情况,Formik提供了一个Array Field组件,可以方便地处理表单数组。下面是一个使用Array Field组件的示例代码:

import { FieldArray } from 'formik';

function MyForm() {
  return (
    <Formik
      initialValues={{ users: [{ name: '', email: '' }] }}
      onSubmit={(values) => {
        console.log(values);
      }}
    >
      {({ values }) => (
        <Form>
          <FieldArray name="users">
            {({ insert, remove, push }) => (
              <div>
                {values.users.map((user, index) => (
                  <div key={index}>
                    <label htmlFor={`users.${index}.name`}>Name</label>
                    <Field name={`users.${index}.name`} type="text" />
                    <label htmlFor={`users.${index}.email`}>Email</label>
                    <Field name={`users.${index}.email`} type="email" />
                    <button type="button" onClick={() => remove(index)}>
                      Remove
                    </button>
                  </div>
                ))}
                <button type="button" onClick={() => push({ name: '', email: '' })}>
                  Add User
                </button>
              </div>
            )}
          </FieldArray>
          <button type="submit">Submit</button>
        </Form>
      )}
    </Formik>
  );
}

在这个示例代码中,我们使用了FieldArray组件来处理名为users的表单数组。我们可以使用map方法来遍历数组,并为每个数组项渲染一个输入框和删除按钮。同时,我们还使用了push方法来添加新的数组项。

6.2 动态添加和删除表单域

在 Formik 中使用表单数组可以帮助我们轻松地处理复杂表单需求。例如,假设我们需要让用户输入他们所有的电话号码,而不仅仅是一个电话号码。这时候,我们可以使用一个表单数组来动态添加和删除电话号码输入框。

下面是一个简单的示例代码,演示了如何使用表单数组。

import React from 'react';
import { Formik, Field, FieldArray } from 'formik';
import * as Yup from 'yup';

const SignupForm = () => (
  <div>
    <h1>Signup Form</h1>
    <Formik
      initialValues={{ phoneNumber: [''] }}
      validationSchema={Yup.object().shape({
        phoneNumber: Yup.array().of(Yup.string().required('Phone number is required')),
      })}
      onSubmit={values => {
        console.log(values);
      }}
      render={({ values }) => (
        <form onSubmit={handleSubmit}>
          <FieldArray name="phoneNumber">
            {({ push, remove }) => (
              <div>
                {values.phoneNumber.map((phoneNumber, index) => (
                  <div key={index}>
                    <Field name={`phoneNumber.${index}`} />
                    {index > 0 && (
                      <button type="button" onClick={() => remove(index)}>
                        Remove
                      </button>
                    )}
                  </div>
                ))}
                <button type="button" onClick={() => push('')}>
                  Add Phone Number
                </button>
              </div>
            )}
          </FieldArray>
          <button type="submit">Submit</button>
        </form>
      )}
    />
  </div>
);

export default SignupForm;

在上面的代码中,我们使用了 FieldArray 组件来创建一个表单数组。在表单数组中,我们可以使用 map 方法来遍历数组中的每个元素,并为每个元素创建一个表单域。我们还可以使用 pushremove 方法来添加和删除表单数组中的元素。

我们还可以使用 FieldArray 组件的 render 方法来自定义表单数组的渲染方式。在上面的代码中,我们将 pushremove 方法作为 FieldArray 的子组件传递,这样我们就可以在点击“Add Phone Number”按钮时添加一个新的电话号码输入框,并在每个电话号码输入框后面添加一个“Remove”按钮,以便用户可以删除电话号码输入框。

除了使用表单数组之外,我们还可以使用 Formik 的 FieldArray 组件处理动态添加和删除表单域的需求。

下面是一个使用FieldArray的示例代码:

import React from 'react';
import { Formik, Form, Field, FieldArray } from 'formik';
import * as Yup from 'yup';

const SignupForm = () => (
  <Formik
    initialValues={{
      name: '',
      email: '',
      phones: ['']
    }}
    validationSchema={Yup.object({
      name: Yup.string()
        .required('Required'),
      email: Yup.string()
        .email('Invalid email address')
        .required('Required'),
      phones: Yup.array()
        .of(Yup.string()
          .matches(/^\d{10}$/, 'Invalid phone number')
        )
    })}
    onSubmit={(values, { setSubmitting }) => {
      setTimeout(() => {
        alert(JSON.stringify(values, null, 2));
        setSubmitting(false);
      }, 400);
    }}
  >
    {({ values }) => (
      <Form>
        <label htmlFor="name">Name</label>
        <Field name="name" type="text" />
        <label htmlFor="email">Email</label>
        <Field name="email" type="email" />
        <FieldArray name="phones">
          {({ insert, remove, push }) => (
            <div>
              {values.phones.length > 0 &&
                values.phones.map((phone, index) => (
                  <div key={index}>
                    <Field name={`phones.${index}`} />
                    {index > 0 && (
                      <button type="button" onClick={() => remove(index)}>Remove</button>
                    )}
                  </div>
                ))}
              <button type="button" onClick={() => push('')}>Add Phone Number</button>
            </div>
          )}
        </FieldArray>
        <button type="submit">Submit</button>
      </Form>
    )}
  </Formik>
);

在上面的示例代码中,我们使用了FieldArray组件来为表单中的电话号码创建一个动态数组。该数组的每个元素都是一个字符串类型的电话号码。在validation Schema中,我们使用了Yup.array()方法来验证该数组的值。如果验证失败,则会出现错误消息。在渲染表单时,我们可以使用map函数来为数组中的每个元素创建一个嵌套表单,并使用insertremove方法来添加和删除元素。

7.Modal中使用了Formik

在Modal中使用Formik后,如何提交呢?
在其他组件中操作该组件,我们通常可以用ref.current获取实例,进而调用方法或属性实现。
那么我们就可以给 Form 创建一个ref:
hooks中:

const formRef = React.useRef();

类组件中:

constructor(props){
	super(props);
	this.formRef=React.createRef();
}

然后,就可以使用ref了,Modal的footer 中:

 		[<Button
          key="save"
          type="primary"
          onClick={() => {
            formRef.current.handleSubmit();
          }}
        >
          保存
        </Button>,
        <Button
          key="reset"
          onClick={() => {
            formRef.current.handleReset();
          }}
        >
          重置
        </Button>,
        ]

完整代码:


const ChargeBackModal = (props) => {
  const formRef = React.useRef();
  // 父组件传入
  const { visible, onClose, cause} = props;
  const initialValues={
	grade:'',
	class:'',
	name:'',
	cause,
  }
  // 渠道交割
  const onSave = async (values) => {
    console.log('values:', values);
    const res = await submitApi(params);
     const { code, message: msg } = res;
     if (code !== '200') {
      message.error(`${msg}||'系统异常'`);
      return;
    }
     message.success(msg);
    onClose();
  };

  const laylout = {
    labelCol: {
      xs: { span: 24 },
      sm: { span: 8 },
    },
    wrapperCol: {
      xs: { span: 24 },
      sm: { span: 16 },
    },
  };
  const tailFormItemLayout = {
    wrapperCol: {
      xs: {
        span: 24,
        offset: 0,
      },
      sm: {
        span: 16,
        offset: 8,
      },
    },
  };
  return (
    <Modal
      visible={visible}
      title="退单"
      maskClosable
      destroyOnClose
      onCancel={onClose}
      footer={[
        <Button
          key="save"
          type="primary"
          onClick={() => {
            formRef.current.handleSubmit();
          }}
        >
          保存
        </Button>,
        <Button
          key="reset"
          onClick={() => {
            formRef.current.handleReset();
          }}
        >
          重置
        </Button>,
      ]}
    >
      <Form initialValues={initialValues} ref={formRef} {...laylout} onSubmit={onSave}>
        <Form.Item label="年级" name="grade" required />
        <Form.Item label="班级" name="class" required />
        <Form.Item label="姓名" name="name" value={currency} disabled />
        <Form.Item label="原因" name="reamrk" required />
        <Form.Item {...tailFormItemLayout}></Form.Item>
      </Form>
    </Modal>
  );
};
export default ChargeBackModal;

8.结论

formik

8.1 总结Formik的优势和核心功能

Formik提供了许多优秀的特性,使得表单处理变得更加简单。其中一些特性包括:

  • 通过集中管理值,降低了表单处理的复杂性。
  • 提供了自动表单提交和验证机制。
  • 提供了可自定义的表单错误处理机制。
  • 提供了可自定义的表单验证机制,允许开发人员使用自己喜欢的验证库。

Formik的核心功能包括值管理、表单提交、表单重置、处理验证和错误。这些功能可以帮助开发人员管理表单,让表单处理变得更加容易和高效。

8.2 下一步行动

如果你对Formik感兴趣,可以尝试以下操作:

  • 访问Formik官方文档,学习更多关于Formik的知识和用法。
  • 将Formik应用到你的项目中,体验其便利性。
  • 在处理复杂表单时,尝试使用Formik的高级特性,如表单数组和动态表单域。
  • 将Yup或其他验证库集成到Formik中,增强表单验证的能力。

总之,Formik是一个功能强大的表单处理库,它提供了许多方便的功能和工具,帮助开发人员更轻松地处理表单。无论是简单表单还是复杂表单,Formik都能够满足你的需求,提高开发效率和代码质量。

formik

9 参考文献

本文参考了以下资料:

Formik documentation.
https://formik.org/docs/overview

Formik with React Tutorial.
https://www.robinwieruch.de/react-formik

Using Formik to handle forms in React.
https://blog.logrocket.com/using-formik-to-handle-forms-in-react/

Formik – Elegant React forms.
https://rangle.io/blog/formik-elegant-forms-in-react/

Yup documentation.
https://github.com/jquense/yup

Building Reusable Forms with Formik and Yup.
https://rangle.io/blog/building-a-reusable-form-with-formik-and-yup/

Handling Complex Forms in React Using Formik, Yup and Field Arrays. https://www.digitalocean.com/community/tutorials/handling-complex-forms-in-react-using-formik-yup-and-field-arrays

这些资料包括官方文档、教程、博客文章和社区贡献的代码示例,提供了广泛的Formik使用和实践经验。读者可以深入了解Formik的优势、核心功能、高级特性和最佳实践,以及使用Yup进行表单验证和处理复杂表单需求的方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Sourcetree是一个非常好用的git客户端,它提供了可视化的界面帮助开发者进行多人协作开发过程中的各种git操作,比如push、pull、add、commit、merge等等。 在使用Sourcetree之前,你需要先下载、安装和配置好环境。然后你可以打开Sourcetree,它会展示一个初始界面,其中包含了本地仓库的相关信息。 Sourcetree是一个强大的工具,但本文只介绍了一些常用的功能,并没有记录一些使用频率较低的功能。工具的目的是帮助我们提高工作效率,所以我们只需要掌握最有用的部分即可。 在正文部分,你可以了解到Sourcetree的各种功能,以及对应的git命令和如何使用这些功能。它详细介绍了各种常用操作,帮助你更好地使用Sourcetree进行版本控制。[1,2] 使用Sourcetree可以很方便地进行分支的检出和关联远程分支。当你使用命令行检出分支后,你还需要执行一些操作来与远程分支进行关联。但是Sourcetree非常友好,当你点击克隆按钮时,它会自动帮助你与远程仓库进行关联。 总之,Sourcetree是一个功能强大且易于使用的git客户端,它为开发者提供了可视化的界面来管理和执行各种git操作,帮助我们更高效地进行协同开发。[1,2,3]<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Sourcetree 使用详解](https://blog.csdn.net/weixin_43837354/article/details/105936140)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [SourceTree使用教程图文详解](https://blog.csdn.net/qq_41153943/article/details/120814918)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvin880828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值