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.结论

formik

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

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

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

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

7.2 下一步行动

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

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

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

formik

8 参考文献

本文参考了以下资料:

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进行表单验证和处理复杂表单需求的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/18178.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OSI七层网络模型+TCP/IP四层模型

OSI七层模型&#xff1a; 物理层&#xff1a;主要定义物理设备标准&#xff0c;如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流&#xff08;就是由1、0转化为电流强弱来进行传输&#xff0c;到达目的地后再转化为1、0&#xff0c;也就…

2023年淮阴工学院五年一贯制专转本财务管理基础考试大纲

2023年淮阴工学院五年一贯制专转本财务管理基础考试大纲 一、考核对象 本课程的考核对象为五年一贯制高职专转本财务管理专业入学考试普通在校生考生。 二、考核方式 本课程考核采用闭卷笔试的方式。 三、命题依据及原则 1、命题依据 本课程考核命题教材为靳磊编著&…

1_5 pytorch操作

一、torch 算子 1、torch.nn.functional.affine_grid(theta, size) 给定一组仿射矩阵(theta)&#xff0c;生成一个2d的采样位置(流场)&#xff0c;通常与 grid_sample() 结合使用,用于空间仿射变换网络&#xff0c;用于对2D或3D数据进行仿射变换。 输入&#xff1a;theta(Te…

AIGPT中文版(无需魔法,直接使用)不愧是生活工作的好帮手。

AIGPT AIGPT是一款非常强大的人工智能技术的语言处理工具软件&#xff0c;它具有 AI绘画 功能、AI写作、写论文、写代码、哲学探讨、创作等功能&#xff0c;可以说是生活和工作中的好帮手。 我们都知道使用ChatGPT是需要账号以及使用魔法的&#xff0c;其中的每一项对我们初学…

使用JPA自动生成代码(轻松上手看了就会版)

目录 背景&#xff1a;方案概念&#xff1a;JPA 的主要作用 jpa简单使用&#xff08;Springboot项目&#xff09;jpa进阶使用总结 背景&#xff1a; 项目需要自动生成sql代码&#xff0c;不需要写sql语句&#xff0c;能够自动进行查询&#xff0c;我想到了JPA。 方案 概念&a…

Linux驱动编程(分层分离编程思想)

1、面向对象 ⚫ 字符设备驱动程序抽象出一个 file_operations 结构体&#xff1b; ⚫ 我们写的程序针对硬件部分抽象出 led_operations 结构体。 2、分层 上层实现硬件无关的操作&#xff0c;比如注册字符设备驱动&#xff1a;leddrv.c 下层实现硬件相关的操作&#xff0c;比如…

Makefile零基础教学(一)初识makefile

从这篇文章开始就开始进入 Makefile 的零基础教程&#xff0c;相信只要看了本教程的都可以对 Makefile 有一个清晰的理解和正确的运用。那么现在就开始我们的 Makefile 学习之路。 文章目录 一、什么是 Makefile&#xff0c;优点&#xff1f;二、什么是 make, 为什么使用make?…

Linux学习记录——이십이 进程信号(1)

文章目录 1、了解信号2、了解信号处理3、信号产生1、键盘按键产生2、系统接口产生3、软件条件产生4、硬件异常 4、Core和Term的区别5、信号保存1、在系统中的表现形式2、信号集操作函数1、sigprocmask2、sigpending 6、重谈地址空间7、信号处理与捕捉sigaction 1、了解信号 信…

MySQL索引、事务与存储引擎

数据库索引 是一个排序的列表&#xff0c;存储着索引值和这个值对应的物理地址&#xff0c;在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址&#xff08;类似于C语言的链表通过指针指向数据记录的内存地址&#xff09;无需对整个表进行扫描&#xff0c;而是先通…

IS210AEBIH3BEC隔离器用于变压器等高压设备

IS210AEBIH3BEC隔离器用于变压器等高压设备 隔离器可以根据在电力系统中的位置进行分类 母线侧隔离器——隔离器直接连接到主母线线路侧隔离器 - 隔离器将放置在任何馈线的线路侧Transfer bus side isolator – isolator will be directly connected with the transfer bus S…

【LeetCode】1143. 最长公共子序列

1.问题 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff0…

怎么让chatGTP写论文-chatGTP写论文工具

chatGTP如何写论文 ChatGPT是一个使用深度学习技术训练的自然语言处理模型&#xff0c;可以用于生成自然语言文本&#xff0c;例如对话、摘要、文章等。作为一个人工智能技术&#xff0c;ChatGPT可以帮助你处理一些文字内容&#xff0c;但并不能代替人类的创造性思考和判断。以…

手机录屏怎么操作?有哪些好用的方法

在现代科技的时代&#xff0c;手机录屏已经成为了常见的操作。这项技术允许我们在手机上录制视频并分享给他人。但是&#xff0c;很多人可能并不知道如何进行手机录屏。下面我们将介绍手机录屏的操作方法和一些值得推荐的工具。 手机录屏操作方法 对于iOS用户&#xff0c;可以…

Ribbon负载均衡

目录 1.Ribbon负载均衡 1.1.负载均衡原理 1.2.源码跟踪 1&#xff09;LoadBalancerIntercepor 2&#xff09;LoadBalancerClient 3&#xff09;负载均衡策略IRule 4&#xff09;总结 1.3.负载均衡策略 1.3.1.负载均衡策略 1.3.2.自定义负载均衡策略 1.4.饥饿加载 1.R…

InnoDB 与MyISAM 的区别

MyISAM和InnoDB都是Mysql里面的两个存储引擎。 在Mysql里面&#xff0c;存储引擎是可以自己扩展的&#xff0c;它的本质其实是定义数据存储的方式以及数据读取的实现逻辑。 不同存储引擎本身的特性&#xff0c;使得我们可以针对性的选择合适的引擎来实现不同的业务场景。从而获…

Java企业级信息系统开发01—采用spring配置文件管理bean

文章目录 一、Web开发技术二、spring框架&#xff08;一&#xff09;spring官网&#xff08;二&#xff09;spring框架优点&#xff08;三&#xff09;Spring框架核心概念1、IoC&#xff08;Inversion of Control&#xff09;和容器2、AOP&#xff08;Aspect-Oriented Programm…

间谍软件开发商利用漏洞利用链攻击移动生态系统

导语&#xff1a;间谍软件开发商结合使用了零日漏洞和已知漏洞。谷歌TAG的研究人员督促厂商和用户应加快给移动设备打补丁的步伐。 间谍软件开发商利用漏洞利用链攻击移动生态系统去年&#xff0c;几家商业间谍软件开发商开发并利用了针对 iOS 和安卓用户的零日漏洞。然而&…

【Python】什么是爬虫,爬虫实例

有s表示加密的访问方式 一、初识爬虫 什么是爬虫 网络爬虫&#xff0c;是一种按照一定规则&#xff0c;自动抓取互联网信息的程序或者脚本。由于互联网数据的多样性和资源的有限性&#xff0c;根据用户需求定向抓取相关网页并分析已成为如今主流的爬取策略爬虫可以做什么 你可以…

stream的collectors

起因的话&#xff0c;新进公司&#xff0c;看见了一段有意思的代码。 public final class MyCollectors {private MyCollectors() {}static final Set<Collector.Characteristics> CH_ID Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_F…

从点赞到数字货币:揭秘Diem币与Facebook的联系

大家都知道Facebook是一个全球知名的社交媒体平台&#xff0c;但你是否听说过与Facebook有关的数字货币Diem币呢&#xff1f;或许你会想&#xff0c;从点赞到数字货币&#xff0c;这是怎么回事&#xff1f;别着急&#xff0c;让我们一起揭秘Diem币与Facebook的联系。 首先&…