如何使用 yup 和 formik 构建一个带有验证的简单表单(适合初学者)这篇文章将分为 3 个部分该表单的最终代码将是恭喜,您刚刚完成了这个简单的教程。

2025-06-07

如何使用 yup 和 formik 构建一个带有验证功能的简单表单(适合初学者)

这篇文章将分为 3 个部分

该表单的最终代码为




恭喜,您刚刚完成了这个简单的教程。

试想一下,填写一份验证不充分的表格可能会带来多大的挫败感 :( 您可能会离开该页面。从表面上看,表单的构建非常简单,但在验证表单时,可能会有点挑战。

几周前,我尝试创建一个带验证功能的表单,但遇到了一些困难。最终找到方法后,我意识到写一篇关于它的文章会很棒,因为可能有很多人也面临着同样的挑战。

今天,我将向您介绍如何使用以下字段构建表单:

姓名

年龄

电子邮件

密码

确认密码

**按钮禁用,直到所有验证都得到满足

这篇文章将分为 3 个部分

  1. 构建表单
  2. 构建验证
  3. 点击提交按钮应该将用户带到欢迎页面

第一部分

让我们首先在 React 中创建表单

创建表单而不将表单字段拆分成组件



import React from "react";

function Form() {
  return (
    <form>
      <div>
        <label htmlFor="name">Name</label>
        <input type="text" name="name" id="name" placeholder="Please Enter your name" />
      </div>
      <div>
        <label htmlFor="age">Age</label>
        <input type="number" name="age" id="age" placeholder="Please Enter your age" />
      </div>
      <div>
        <label htmlFor="email">Email</label>
        <input type="email" name="age" id="email" placeholder="Please Enter your email" />
      </div>
      <div>
        <label htmlFor="password">Password</label>
        <input
          type="password"
          name="password"
          id="password"
          placeholder="Please Enter your password"
        />
      </div>
      <div>
        <label htmlFor="confirm-password">Confirm Password</label>
        <input
          type="password"
          name="confirm-password"
          id="confirm-password"
          placeholder="Please Confirm your password"
        />
      </div>
      <button>Submit</button>
    </form>
  );
}

export default Form;


Enter fullscreen mode Exit fullscreen mode

看起来是这样的

替代文本

为了减少代码重复,让我们创建一个表单字段组件,其以:labelName、name、type 和 placeholder 作为 Props。

表单字段组件如下所示:



import React from "react";

function FormField({ name, label, ...rest }) {
  return (
    <div >
      <label htmlFor={name}>{label}</label>
      <input  id={name} name={name} {...rest} />
    </div>
  );
}

export default FormField;



Enter fullscreen mode Exit fullscreen mode

重构我们的表单组件将得到:



import React from "react";
import FormField from "./FormField";

function Form() {
  return (
    <form>
      <FormField
        label="Name"
        type="text"
        name="name"
        placeholder="Please Enter your name"
      />
      <FormField
        label="Age"
        type="number"
        name="age"
        placeholder="Please Enter your age"
      />
      <FormField
        label="Email"
        type="email"
        name="email"
        placeholder="Please Enter your email"
      />
      <FormField
        label="Password"
        type="password"
        name="password"
        placeholder="Please Enter your password"
      />
      <FormField
        label="Confirm Password"
        type="password"
        name="confirm-password"
        placeholder="Please Confirm your password"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

export default Form;


Enter fullscreen mode Exit fullscreen mode

第二部分

此表单的验证如下:

  1. 姓名:姓名不得少于3个字符
  2. 电子邮件:必须是有效的电子邮件地址
  3. 年龄:必须至少 18 岁且最多 60 岁
  4. 密码:必须至少包含一个大写字母、一个数字、一个特殊字符且不少于8个字符
  5. 确认密码:必须与密码字段匹配

首先,我们需要安装并导入 2 个库到我们的应用程序中。

  1. Yup:Yup 是一个用于值解析和验证的 JavaScript 模式构建器。https ://www.npmjs.com/package/yup
  2. Formik:Formik 是一个帮助您管理表单状态、处理验证、错误消息和表单提交的库。https ://jaredpalmer.com/formik/docs/overview

接下来,我们将为表单字段创建初始值



const initialValues = {
  name: "",
  age: "",
  email: "",
  password: "",
  confirmPassword: ""
};


Enter fullscreen mode Exit fullscreen mode

之后,我们使用 yup 创建验证模式对象



const validationSchema = yup.object().shape({
  name: yup
    .string()
    .required("Name is a required field")
    .min(3, "Name must be at least 3 characters"),
  age: yup
    .number()
    .required("Please supply your age")
    .min(18, "You must be at least 18 years")
    .max(60, "You must be at most 60 years"),
  email: yup
    .string()
    .email()
    .required("Email is a required field"),
  password: yup
    .string()
    .required("Please enter your password")
    .matches(
      /^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/,
      "Password must contain at least 8 characters, one uppercase, one number and one special case character"
    ),
  confirmPassword: yup
    .string()
    .required("Please confirm your password")
    .when("password", {
      is: password => (password && password.length > 0 ? true : false),
      then: yup.string().oneOf([yup.ref("password")], "Password doesn't match")
    })
});


Enter fullscreen mode Exit fullscreen mode

将所有内容整合到 Form 组件中,即可得到



import React from "react";
import { useFormik } from "formik";
import * as yup from "yup";
import FormField from "./FormField";


//setting the initial values
const initialValues = {
  name: "",
  age: "",
  email: "",
  password: "",
  confirmPassword: ""
};

//creating the validation schema
const validationSchema = yup.object().shape({
  name: yup
    .string()
    .required("A name is required")
    .min(2, "Name must be at least 2 characters"),
  age: yup
    .number()
    .required("Please supply your age")
    .min(18, "You must be at least 18 years")
    .max(60, "You must be at most 60 years"),
  email: yup
    .string()
    .email()
    .required("Email is a required field"),
  password: yup
    .string()
    .required("Please enter your password")
    .matches(
      /^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/,
      "Password must contain at least 8 characters, one uppercase, one number and one special case character"
    ),
  confirmPassword: yup
    .string()
    .required("Please confirm your password")
    .when("password", {
      is: password => (password && password.length > 0 ? true : false),
      then: yup.string().oneOf([yup.ref("password")], "Password doesn't match")
    })
});

function Form({ onSubmit }) {
  //using useFormik 
  const formik = useFormik({
    initialValues,
    validationSchema,
    onSubmit
  });

  return (
    <form onSubmit={formik.handleSubmit}>
      <FormField
        label="Name"
        type="text"
        name="name"
        placeholder="Please Enter your name"
      />
      <FormField
        label="Age"
        type="number"
        name="age"
        placeholder="Please Enter your age"
      />
      <FormField
        label="Email"
        type="email"
        name="email"
        placeholder="Please Enter your email"
      />
      <FormField
        label="Password"
        type="password"
        name="password"
        placeholder="Please Enter your password"
      />
      <FormField
        label="Confirm Password"
        type="password"
        name="confirm-password"
        placeholder="Please Confirm your password"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

export default Form;


Enter fullscreen mode Exit fullscreen mode

** 请注意,我们将回调传递到onSubmit了 useFormik 钩子中,也传递onSubmit={formik.handleSubmit}到了表单中。

至此,我们的任务几乎完成了,我们只需要利用一些道具并确保错误消息显示出来

我们将使用 getFieldProps。



  const nameProps = formik.getFieldProps("name");
  const ageProps = formik.getFieldProps("age");
  const emailProps = formik.getFieldProps("email");
  const passwordProps = formik.getFieldProps('password');
  const confirmPasswordProps = formik.getFieldProps('confirmPassword');


Enter fullscreen mode Exit fullscreen mode

最后,我们需要在验证不通过时显示错误消息。例如,对于姓名字段,使用 formik 将会是



{formik.touched.name && formik.errors.name ? (
        <div>{formik.errors.name}</div>
      ) : null}


Enter fullscreen mode Exit fullscreen mode

该表单的最终代码为



import React from "react";
import { useFormik } from "formik";
import * as yup from "yup";
import FormField from "./FormField";

//setting the initial values
const initialValues = {
  name: "",
  age: "",
  email: "",
  password: "",
  confirmPassword: ""
};

//creating the validation schema
const validationSchema = yup.object().shape({
  name: yup
    .string()
    .required("A name is required")
    .min(2, "Name must be at least 2 characters"),
  age: yup
    .number()
    .required("Please supply your age")
    .min(18, "You must be at least 18 years")
    .max(60, "You must be at most 60 years"),
  email: yup
    .string()
    .email()
    .required("Email is a required field"),
  password: yup
    .string()
    .required("Please enter your password")
    .matches(
      /^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/,
      "Password must contain at least 8 characters, one uppercase, one number and one special case character"
    ),
  confirmPassword: yup
    .string()
    .required("Please confirm your password")
    .when("password", {
      is: password => (password && password.length > 0 ? true : false),
      then: yup.string().oneOf([yup.ref("password")], "Password doesn't match")
    })
});

function Form({ onSubmit }) {
  //using useFormik
  const formik = useFormik({
    initialValues,
    validationSchema,
    onSubmit
  });

  //use formik.getFieldProps for input fields
  const nameProps = formik.getFieldProps("name");
  const ageProps = formik.getFieldProps("age");
  const emailProps = formik.getFieldProps("email");
  const passwordProps = formik.getFieldProps("password");
  const confirmPasswordProps = formik.getFieldProps("confirmPassword");

  /**
   * getFieldProps is a way to reduce boilerplate (repetitive) code.
   * It returns helper methods like `onChange`, `onBlur`, `value`, `name`.
   *
   * @see Formik https://jaredpalmer.com/formik/docs/tutorial#getfieldprops
   */
  return (
    <form onSubmit={formik.handleSubmit}>
      <FormField
        label="Name"
        type="text"
        placeholder="Please Enter your name"
        {...nameProps}
      />
      {formik.touched.name && formik.errors.name ? (
        <div>{formik.errors.name}</div>
      ) : null}
      <FormField
        label="Age"
        type="number"
        {...ageProps}
        placeholder="Please Enter your age"
      />
      {formik.touched.age && formik.errors.age ? (
        <div>{formik.errors.age}</div>
      ) : null}
      <FormField
        label="Email"
        type="email"
        placeholder="Please Enter your email"
        {...emailProps}
      />
      {formik.touched.email && formik.errors.email ? (
        <div>{formik.errors.email}</div>
      ) : null}
      <FormField
        label="Password"
        type="password"
        placeholder="Please Enter your password"
        {...passwordProps}
      />
      {formik.touched.password && formik.errors.password ? (
        <div>{formik.errors.password}</div>
      ) : null}
      <FormField
        label="Confirm Password"
        type="password"
        placeholder="Please Confirm your password"
        {...confirmPasswordProps}
      />
      {formik.touched.confirmPassword && formik.errors.confirmPassword ? (
        <div>{formik.errors.confirmPassword}</div>
      ) : null}
      <button type="submit" disabled={!(formik.isValid && formik.dirty)}>Submit</button>
    </form>
  );
}

export default Form;



Enter fullscreen mode Exit fullscreen mode

请注意,为了在满足所有表单验证之前禁用按钮,我仅将:disabled={!(formik.isValid && formik.dirty)}作为 prop 传递到按钮中。

第 3 部分

与所有表单一样,点击提交按钮后,您希望用户转到另一个页面。我将向您展示如何具体实现这一点。

(如果您需要有关路由的进一步解释,在我的下一篇博文中,我将逐步指导您如何在 React 中设置路由)。

现在,您需要做的是:

  1. 安装“react-router-dom”
  2. 创建您希望用户在提交表单后看到的组件或页面。在本例中,我将创建一个欢迎页面


import React from "react";

function Welcome() {
  return (
    <div>
      <h3>Hello and welcome</h3>
    </div>
  );
}

export default Welcome;


Enter fullscreen mode Exit fullscreen mode

在应用程序中输入:



import React from "react";
import { Route, BrowserRouter as Router, Switch } from "react-router-dom";
import Form from "./Form";
import Welcome from "./Welcome";

export default function App() {
return (
<Router>
<Switch>
<Route
exact
path="/"
render={props => (
<Form
onSubmit={value => {
props.history.push("/welcome");
}}
/>
)}
/>
<Route exact path="/welcome" component={Welcome} />
</Switch>
</Router>
);
}

Enter fullscreen mode Exit fullscreen mode




恭喜,您刚刚完成了这个简单的教程。

我希望这真的有助于您了解如何使用 yup 和 formik 从头开始​​构建带有验证的表单。

如果您发现这有用,请发表评论并查看我的其他帖子。

文章来源:https://dev.to/_estheradebayo/how-to-build-a-simple-form-with-validation-using-yup-and-formik-beginner-friend-521j
PREV
Vue.js 开发人员的 React 指南
NEXT
5 个增强命令行功能的工具(系列第 2 部分)