使用 Formik 构建 React 表单的 3 种方法(第一部分)
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
Formik 是最流行的表单构建库之一。它能帮助开发者用极少的代码完成许多操作,例如表单状态管理、验证和错误处理。本教程将向您展示使用 Formik 构建 React 表单的三种方法。
构建形式的痛苦
构建 React 表单听起来很简单,但实际上并非如此。它涉及很多方面。通常最简单的部分是搭建表单。接下来才是难点。这包括表单状态管理和处理表单中填写的值,也包括准备表单的初始状态。
有了这些信息,你需要编写函数来处理这些字段,以保持表单状态的最新状态。接下来是验证。你必须确保所有值都是合法有效的。这可能需要一些验证逻辑,包括正则表达式。作为验证的一部分,你还必须确保所有必填字段的值都有效。
如果某个值无效,或者必填但缺失怎么办?发生这种情况时,您必须找出哪个值无效,并显示该字段的正确错误消息。但这还没完。您还需要确保当值有效时,错误消息消失。只有确保所有这些步骤都已完成,才能继续提交表单。
使用 Formik 构建 React 表单
如果你觉得这一切很麻烦,你并不孤单。对于一位 React 开发者来说,这种麻烦反而促使他找到了解决方案。他最终开发的方案就是Formik。Formik的理念是为开发者完成大部分繁重的工作,从而简化 React 表单的构建过程。
这包括构建表单的常规步骤,例如表单状态管理、输入验证、必要时显示错误信息以及处理表单提交。目前,至少有三种方法可以使用 Formik 构建表单。下面,我们将逐一介绍这些方法。
创建简单的表单验证方案
Formik 支持多种表单验证方式。一种方法是自行编写验证逻辑,Formik 将使用该逻辑并处理错误消息。另一种方法是使用验证库。在本教程中,我们将选择第二种方法,并使用名为Yup的验证库。
这个库的作用是帮助你为表单创建验证模式。这个模式本质上是一个对象,其中包含表单中各个字段的验证规则。Formik 可以使用这个基于 Formik 构建的模式,Yup根据其特定的规则验证模式中定义的所有字段。
模式的另一个优点Yup是可以为每条规则指定错误消息。您可以通过将一些文本作为参数传递给规则函数来实现这一点。例如,当字段为必填项时,您可以使用required()函数。要为该规则指定错误消息,请将消息作为参数传递:required('This field is required.')。
本教程中使用的所有表单都将包含三个字段:姓名、电子邮件和密码。所有这些字段均为必填项。我们将在创建的表单架构中指定所有这些信息Yup。对于电子邮件字段,我们还会指定其格式必须与标准电子邮件格式匹配。
import * as Yup from 'yup'
const formSchema = Yup.object().shape({
name: Yup.string().required('First name is required'),
email: Yup.string().email('Invalid email').required('Email is required'),
password: Yup.string().required('Password is required'),
})
使用 Formik 自定义表单
第一种方法是使用 Formik 作为 React 表单的封装器。您需要创建表单以及所有需要的字段组件,包括这些字段的错误信息。Formik 将负责表单状态、验证和错误处理。这种方法只需要 Formik 提供的一个组件Formik。
Formik组件
此Formik组件将作为整个表单的包装器。但这并不意味着它会替换form包裹表单的元素。如果您正在使用该form元素,它将保留。该Formik组件也会包裹此元素。该Formik组件有一些非常有用的属性。
这些属性包括`initialValues` initialValues、 `setState`onSubmit和validationSchema`setState`。`initialValues` 属性initialValues指定一个对象,用于定义所有字段的初始值并创建表单状态。`setState`onSubmit属性允许您为onSubmit事件指定处理函数。`setState`validationSchema属性允许您指定要使用的验证模式。
所有字段(姓名、邮箱和密码)的初始值均为空字符串。目前,为了处理onSubmit事件,我们将使用箭头函数和简单的方法console.log()来记录提交的值。Formik组件使用render-prop 模式,这有助于在 React 组件之间共享代码。不用担心,您无需了解其工作原理。
你只需要知道,它Formik期望它的直接子元素是一个返回某个 React 组件的函数。在本例中,返回的组件将是form元素及其内容。因为我们将使用自定义表单元素,所以我们需要从组件中暴露一些数据Formik以便进行操作。
我们可以通过在返回元素的函数中使用对象解构form来获取这些数据。我们需要的数据是values` <form>`、`<form>` errors、 `<form>` touched、 ` handleBlur<form>`handleChange和`<form> handleSubmit`。`<form>`values是一个包含每个表单字段当前值的对象。我们将使用它来指定 `<input>`value属性的值。
这errors也是一个对象。如果表单中存在任何错误,例如无效或缺失的字段,您都可以在此对象中找到相关信息。该touched对象还指示哪些表单字段已被点击,哪些未被点击。点击的字段意味着有人与该字段进行了交互,该字段获得了焦点。
` handleBlurand`handleChange是输入onBlur和onChange事件的处理程序。这两个事件允许 Formik 跟踪值的变化、更新表单状态、更新“已触摸”状态,并在字段失去焦点时运行验证。`and`handleSubmit是表单事件的处理程序onSubmit。
我们将使用此处理程序来处理元素onSubmit的属性,以便在表单提交时form触发 Formik 的函数。handleSubmit
// Import dependencies:
import { memo } from 'react'
import { Formik } from 'formik'
import * as Yup from 'yup'
// Create form validation schema:
const formSchema = Yup.object().shape({
name: Yup.string().required('First name is required'),
email: Yup.string().email('Invalid email').required('Email is required'),
password: Yup.string().required('Password is required'),
})
// Create the form component:
export const FormCustom = memo(() => {
return (
<Formik
initialValues={{ name: '', email: '', password: '' }}
onSubmit={(values) => {
console.log(values)
}}
validationSchema={formSchema}
>
{({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
}) => <form></form>}
</Formik>
)
})
FormCustom.displayName = 'FormCustom'
表单内容
下一步是将表单内容,也就是各个字段组合起来。这部分会很快很简单。每个字段都将由div一个用作包装器的元素组成。在这个包装器内部会包含 `<field>`label和 ` input<field>` 元素。此外,还会有p一个用于显示错误信息的元素。为了确保一切正常运行,我们需要两样东西。
首先,我们需要为输入name属性使用正确的值。Formik 使用此属性(或id)将每个字段与表单状态中的正确属性关联起来。我们将初始值对象设置为具有属性 `input_properties` name、` input_properties`email和 ` passwordinput_properties`。这意味着我们必须为每个name属性(或id`input_properties`,或两者都使用)使用相同的值。
第二点是onChange输入onBlur事件处理函数。我们需要将 Formik 状态与每个输入框关联起来。这样 Formik 就能跟踪值的变化和失焦事件,并values相应touched地更新状态errors。最后一点是value每个输入框的属性。
这些输入应由 Formik 状态控制。这样就可以将 Formik 状态中的当前值显示为相应输入字段的值。为此,我们将使用values对象及其特定属性来获取每个输入字段的最新正确值。
// ... Previous code
export const FormCustom = memo(() => {
return (
<Formik
initialValues={{ name: '', email: '', password: '' }}
onSubmit={(values) => {
console.log(values)
}}
validationSchema={formSchema}
>
{({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
}) => (
<form onSubmit={handleSubmit} noValidate>
<div>
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
value={values.name}
onChange={handleChange}
onBlur={handleBlur}
/>
</div>
<div>
<label htmlFor="email">Email</label>
<input
type="email"
name="email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
/>
</div>
<div>
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
/>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
)}
</Formik>
)
})
FormCustom.displayName = 'FormCustom'
简单的错误信息
我们已经有了 Formik 和表单状态,还有表单内容。最后剩下的就是错误信息了。其中一部分已经由我们之前用YupFormik 创建的验证模式涵盖。另一部分就是错误信息本身。我们需要告诉 Formik 在哪里显示它们,以及在什么情况下显示。这两件事都很容易做到。
为了解决第一个问题,我们将把每个错误信息放在对应的字段下。我们将使用p元素来显示我们在验证模式中为每条规则定义的文本Yup。显示每条信息的条件如下:我们希望在字段为空或无效时显示错误,但前提是该字段已被输入。
这有助于防止用户打开表单时出现错误。而且,不用担心。Formik 会在表单提交时自动将所有字段设置为已填写状态。因此,如果有人尝试提交空表单,无效字段的错误消息会正确弹出,因为 Formik 会将所有字段设置为已填写状态,并且存在一些错误。
由于我们在验证模式中指定了错误消息,因此我们只需确保 Formik 为每个字段显示正确的错误消息即可。我们将通过使用errors对象和正确的属性(字段名称)来实现这一点。我们将使用对象中的同一属性touched来检查特定字段是否已被修改。
// ... Previous code
export const FormCustom = memo(() => {
return (
<Formik
initialValues={{ name: '', email: '', password: '' }}
onSubmit={(values) => {
console.log(values)
}}
validationSchema={formSchema}
>
{({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
}) => (
<form onSubmit={handleSubmit} noValidate>
<div>
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
value={values.name}
onChange={handleChange}
onBlur={handleBlur}
/>
{/* Add error message for "Name" field */}
{errors.name && touched.name && <p>{errors.name}</p>}
</div>
<div>
<label htmlFor="email">Email</label>
<input
type="email"
name="email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
/>
{/* Add error message for "Email" field */}
{errors.email && touched.email && <p>{errors.email}</p>}
</div>
<div>
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
/>
{/* Add error message for "Password" field */}
{errors.password && touched.password && <p>{errors.password}</p>}
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
)}
</Formik>
)
})
FormCustom.displayName = 'FormCustom'
把它们组合起来
由于 Formik、表单内容和错误信息都已完成,您的自定义 React 表单也已完成。以下是整个表单的完整代码。最后需要完成的是表单提交后的操作。您可以在 Formik 的onSubmit属性及其处理函数中处理此操作。将其替换console.log()为您需要的任何内容。
// Import dependencies:
import { memo } from 'react'
import { Formik } from 'formik'
import * as Yup from 'yup'
// Create form validation schema:
const formSchema = Yup.object().shape({
name: Yup.string().required('First name is required'),
email: Yup.string().email('Invalid email').required('Email is required'),
password: Yup.string().required('Password is required'),
})
// Create the form component:
export const FormCustom = memo(() => {
return (
<Formik
initialValues={{ name: '', email: '', password: '' }}
onSubmit={(values) => {
console.log(values)
}}
validationSchema={formSchema}
>
{({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
}) => (
<form onSubmit={handleSubmit} noValidate>
<div>
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
value={values.name}
onChange={handleChange}
onBlur={handleBlur}
/>
{errors.name && touched.name && <p>{errors.name}</p>}
</div>
<div>
<label htmlFor="email">Email</label>
<input
type="email"
name="email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
/>
{errors.email && touched.email && <p>{errors.email}</p>}
</div>
<div>
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
/>
{errors.password && touched.password && <p>{errors.password}</p>}
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
)}
</Formik>
)
})
FormCustom.displayName = 'FormCustom'
结论:使用 Formik 构建 React 表单的 3 种方法(第一部分)
Formik 库让构建和使用 React 表单变得更加轻松。本教程演示了如何使Formik组件能够与自定义 HTML 元素配合使用。这可以帮助您Formik仅处理状态管理和验证等事务,而其余部分则可以根据您的需要进行自定义。