如何使用 yup 和 formik 构建一个带有验证功能的简单表单(适合初学者)
这篇文章将分为 3 个部分
该表单的最终代码为
恭喜,您刚刚完成了这个简单的教程。
试想一下,填写一份验证不充分的表格可能会带来多大的挫败感 :( 您可能会离开该页面。从表面上看,表单的构建非常简单,但在验证表单时,可能会有点挑战。
几周前,我尝试创建一个带验证功能的表单,但遇到了一些困难。最终找到方法后,我意识到写一篇关于它的文章会很棒,因为可能有很多人也面临着同样的挑战。
今天,我将向您介绍如何使用以下字段构建表单:
姓名
年龄
电子邮件
密码
确认密码
**按钮禁用,直到所有验证都得到满足
这篇文章将分为 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;
看起来是这样的
为了减少代码重复,让我们创建一个表单字段组件,其以: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;
重构我们的表单组件将得到:
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;
第二部分
此表单的验证如下:
- 姓名:姓名不得少于3个字符
- 电子邮件:必须是有效的电子邮件地址
- 年龄:必须至少 18 岁且最多 60 岁
- 密码:必须至少包含一个大写字母、一个数字、一个特殊字符且不少于8个字符
- 确认密码:必须与密码字段匹配
首先,我们需要安装并导入 2 个库到我们的应用程序中。
- Yup:Yup 是一个用于值解析和验证的 JavaScript 模式构建器。https ://www.npmjs.com/package/yup
- Formik:Formik 是一个帮助您管理表单状态、处理验证、错误消息和表单提交的库。https ://jaredpalmer.com/formik/docs/overview
接下来,我们将为表单字段创建初始值
const initialValues = {
name: "",
age: "",
email: "",
password: "",
confirmPassword: ""
};
之后,我们使用 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")
})
});
将所有内容整合到 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;
** 请注意,我们将回调传递到onSubmit
了 useFormik 钩子中,也传递onSubmit={formik.handleSubmit}
到了表单中。
至此,我们的任务几乎完成了,我们只需要利用一些道具并确保错误消息显示出来
我们将使用 getFieldProps。
- getFieldProps 是一种减少样板(重复)代码的方法。
- 它返回辅助方法
onChange
,如onBlur
,,,value
。name
* - @参见福米克https://jaredpalmer.com/formik/docs/tutorial#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');
最后,我们需要在验证不通过时显示错误消息。例如,对于姓名字段,使用 formik 将会是
{formik.touched.name && formik.errors.name ? (
<div>{formik.errors.name}</div>
) : null}
该表单的最终代码为
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;
请注意,为了在满足所有表单验证之前禁用按钮,我仅将:disabled={!(formik.isValid && formik.dirty)}
作为 prop 传递到按钮中。
第 3 部分
与所有表单一样,点击提交按钮后,您希望用户转到另一个页面。我将向您展示如何具体实现这一点。
(如果您需要有关路由的进一步解释,在我的下一篇博文中,我将逐步指导您如何在 React 中设置路由)。
现在,您需要做的是:
- 安装“react-router-dom”
- 创建您希望用户在提交表单后看到的组件或页面。在本例中,我将创建一个欢迎页面
import React from "react";
function Welcome() {
return (
<div>
<h3>Hello and welcome</h3>
</div>
);
}
export default Welcome;
在应用程序中输入:
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>
);
}
恭喜,您刚刚完成了这个简单的教程。
我希望这真的有助于您了解如何使用 yup 和 formik 从头开始构建带有验证的表单。
如果您发现这有用,请发表评论并查看我的其他帖子。
文章来源:https://dev.to/_estheradebayo/how-to-build-a-simple-form-with-validation-using-yup-and-formik-beginner-friend-521j