发布于 2026-01-06 3 阅读
0

使用 Formik 构建 React 表单的 3 种方法(第 1 部分)DEV 的全球展示挑战赛,由 Mux 呈现:展示你的项目!

使用 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'),
})
Enter fullscreen mode Exit fullscreen mode

使用 Formik 自定义表单

第一种方法是使用 Formik 作为 React 表单的封装器。您需要创建表单以及所有需要的字段组件,包括这些字段的错误信息。Formik 将负责表单状态、验证和错误处理。这种方法只需要 Formik 提供的一个组件Formik

Formik组件

Formik组件将作为整个表单的包装器。但这并不意味着它会替换form包裹表单的元素。如果您正在使用该form元素,它将保留。该Formik组件也会包裹此元素。该Formik组件有一些非常有用的属性。

这些属性包括`initialValues` initialValues、 `setState`onSubmitvalidationSchema`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是输入onBluronChange事件的处理程序。这两个事件允许 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'
Enter fullscreen mode Exit fullscreen mode

表单内容

下一步是将表单内容,也就是各个字段组合起来。这部分会很快很简单。每个字段都将由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'
Enter fullscreen mode Exit fullscreen mode

简单的错误信息

我们已经有了 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'
Enter fullscreen mode Exit fullscreen mode

把它们组合起来

由于 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'
Enter fullscreen mode Exit fullscreen mode

结论:使用 Formik 构建 React 表单的 3 种方法(第一部分)

Formik 库让构建和使用 React 表单变得更加轻松。本教程演示了如何使Formik组件能够与自定义 HTML 元素配合使用。这可以帮助您Formik仅处理状态管理和验证等事务,而其余部分则可以根据您的需要进行自定义。

文章来源:https://dev.to/alexdevero/3-ways-to-build-react-forms-with-formik-pt-1-462c