在进行实作之前,先来认识一下 Formik 吧~
如标题所说,Formik 是一个表单函式库,而且还是 React 官方推荐的,相似的还有 Redux Form、React Final Form 等。并且 Formik 还可以搭配 Yup 撰写验证规则、讯息。
透过这些第三方的表单函式库可以帮助我们处理 Input 的事件追踪、验证 Input value、透过 React Context 管理 Form 的 state及避免许多重复性值的程序码。
现在我们要来用 React 和 Formik 建立一个表单出来。
本篇教学从 Formik 官网文件的教学部分 改写而来
const SimpleForm = () => {
return (
<form>
<label htmlFor="name">Your Name</label>
<input type="text" id="name" />
<label htmlFor="email">Your E-Mail</label>
<input type="email" id="email" />
<button type="submit">Submit</button>
</form>
);
};
透过这个 hook 去管理表单的 state 和一些函式。
import { useFormik } from "formik";
const SimpleForm = () => {
const formik = useFormik({
initialValues: {
name: "",
email: ""
},
onSubmit: (values) => {
console.log(values);
}
});
return (
<form onSubmit={formik.handleSubmit}>
<label htmlFor="name">Your Name</label>
<input
type="text"
id="name"
name="name"
onChange={formik.handleChange}
value={formik.values.name}
/>
<label htmlFor="email">Your E-Mail</label>
<input
type="email"
id="email"
name="email"
onChange={formik.handleChange}
value={formik.values.email}
/>
<button type="submit">Submit</button>
</form>
);
};
上一个步骤我们是可以直接送出表单看到值,现在我们针对表单输入内容进行验证,因此建立一个验证函式 validate。
将这个验证函式加入到 useFormik 的参数物件内,会在每次触发 onChange 和 onBlur 事件时做验证。
在後面的步骤,会改用 Yup 做验证
完成的表单元件如下:
import { useFormik } from "formik";
import "./styles.css";
const emailRule = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/;
const validate = (values) => {
const errors = {};
if (!values.name) {
errors.name = "Name must not be empty.";
} else if (values.name.length > 15) {
errors.name = "Must be 15 characters or less.";
}
if (!values.email) {
errors.email = "Email must not be empty.";
} else if (!emailRule.test(values.email)) {
errors.email = "Please enter a valid email.";
}
return errors;
};
const SimpleForm = () => {
const formik = useFormik({
initialValues: {
name: "",
email: ""
},
validate,
onSubmit: (values, { resetForm }) => {
console.log(values);
resetForm();
}
});
const showNameError = formik.touched.name && formik.errors.name;
const showEmailError = formik.touched.email && formik.errors.email;
return (
<form onSubmit={formik.handleSubmit}>
<label htmlFor="name">Your Name</label>
<input
type="text"
id="name"
name="name"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.name}
className={showNameError ? "invalid" : ""}
/>
{showNameError ? (
<p className="error-text">{formik.errors.name}</p>
) : null}
<label htmlFor="email">Your E-Mail</label>
<input
type="email"
id="email"
name="email"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
className={showEmailError ? "invalid" : ""}
/>
{showEmailError ? (
<p className="error-text">{formik.errors.email}</p>
) : null}
<button type="submit">Submit</button>
</form>
);
};
export default SimpleForm;
虽然上个步骤的表单已经算完成了,不过我们来试试使用 Yup 吧!
将 validationSchema 和验证规则写在 useFormik 物件参数内即可。
import { useFormik } from "formik";
import * as Yup from "yup";
import "./styles.css";
const SimpleForm = () => {
const formik = useFormik({
initialValues: {
name: "",
email: ""
},
validationSchema: Yup.object({
name: Yup.string()
.max(15, "Must be 15 characters or less.")
.required("Name must not be empty."),
email: Yup.string()
.email("Please enter a valid email.")
.required("Email must not be empty.")
}),
onSubmit: (values, { resetForm }) => {
console.log(values);
resetForm();
}
});
const showNameError = formik.touched.name && formik.errors.name;
const showEmailError = formik.touched.email && formik.errors.email;
return (
<form onSubmit={formik.handleSubmit}>
<label htmlFor="name">Your Name</label>
<input
type="text"
id="name"
name="name"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.name}
className={showNameError ? "invalid" : ""}
/>
{showNameError ? (
<p className="error-text">{formik.errors.name}</p>
) : null}
<label htmlFor="email">Your E-Mail</label>
<input
type="email"
id="email"
name="email"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
className={showEmailError ? "invalid" : ""}
/>
{showEmailError ? (
<p className="error-text">{formik.errors.email}</p>
) : null}
<button type="submit">Submit</button>
</form>
);
};
export default SimpleForm;
目前已经完成了表单的验证,不过会发现到每个输入栏都有一样的 onChange={formik.handleChange}
、onBlur={formik.handleBlur}
等重复的程序码,这时就可以使用 getFieldProps() 去减少这些程序码。
// 原本的程序码
<input
type="text"
id="name"
name="name"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.name}
className={showNameError ? "invalid" : ""}
/>
<input
type="email"
id="email"
name="email"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
className={showEmailError ? "invalid" : ""}
/>
// 加入 getFieldProps()
<input
type="text"
id="name"
name="name"
{...formik.getFieldProps("name")}
className={showNameError ? "invalid" : ""}
/>
<input
type="email"
id="email"
name="email"
{...formik.getFieldProps("email")}
className={showEmailError ? "invalid" : ""}
/>
在前面的实作,我们是透过 useFormik 去了解怎麽将表单加入验证功能,而现在我们要进行改写,会用到一个有使用到 React Context 的 Formik 的元件去取代 useFormik hook。
官网提供的关於 Formik 元件的程序码:
import React from 'react';
import { useFormik } from 'formik';
// Create empty context
const FormikContext = React.createContext({});
// Place all of what’s returned by useFormik into context
export const Formik = ({ children, ...props }) => {
const formikStateAndHelpers = useFormik(props);
return (
<FormikContext.Provider value={formikStateAndHelpers}>
{typeof children === 'function'
? children(formikStateAndHelpers)
: children}
</FormikContext.Provider>
);
};
以下是改写的结果,Formik 元件接受了一个函式做为它的 children:
import { Formik } from "formik";
import * as Yup from "yup";
import "./styles.css";
const SimpleForm = () => {
return (
<Formik
initialValues={{ name: "", email: "" }}
validationSchema={Yup.object({
name: Yup.string()
.max(15, "Must be 15 characters or less.")
.required("Name must not be empty."),
email: Yup.string()
.email("Please enter a valid email.")
.required("Email must not be empty.")
})}
onSubmit={(values, { resetForm }) => {
console.log(values);
resetForm();
}}
>
{(formik) => (
<form onSubmit={formik.handleSubmit}>
<label htmlFor="name">Your Name</label>
<input
type="text"
id="name"
name="name"
{...formik.getFieldProps("name")}
className={
formik.touched.name && formik.errors.name ? "invalid" : ""
}
/>
{formik.touched.name && formik.errors.name ? (
<p className="error-text">{formik.errors.name}</p>
) : null}
<label htmlFor="email">Your E-Mail</label>
<input
type="email"
id="email"
name="email"
{...formik.getFieldProps("email")}
className={
formik.touched.email && formik.errors.email ? "invalid" : ""
}
/>
{formik.touched.email && formik.errors.email ? (
<p className="error-text">{formik.errors.email}</p>
) : null}
<button type="submit">Submit</button>
</form>
)}
</Formik>
);
};
export default SimpleForm;
注意把 useFormik 的参数物件移到 Formik 元件内时要改成 JSX 语法
最後一个步骤,加入一些 formik 提供的元件,让程序码再次变更精简!
import { Formik, Field, Form, ErrorMessage } from "formik";
import * as Yup from "yup";
import "./styles.css";
const SimpleForm = () => {
return (
<Formik
initialValues={{ name: "", email: "" }}
validationSchema={Yup.object({
name: Yup.string()
.max(15, "Must be 15 characters or less.")
.required("Name must not be empty."),
email: Yup.string()
.email("Please enter a valid email.")
.required("Email must not be empty.")
})}
onSubmit={(values, { resetForm }) => {
console.log(values);
resetForm();
}}
>
{(formik) => (
<Form onSubmit={formik.handleSubmit}>
<label htmlFor="name">Your Name</label>
<Field
name="name"
render={({ field, meta }) => (
<input
type="text" {...field}
className={meta.error ? "invalid" : ""}
/>
)}
/>
<ErrorMessage name="name">
{(err) => <p className="error-text">{err}</p>}
</ErrorMessage>
<label htmlFor="email">Your E-Mail</label>
<Field
name="email"
render={({ field, meta }) => (
<input
type="text" {...field}
className={meta.error ? "invalid" : ""}
/>
)}
/>
<ErrorMessage name="email">
{(err) => <p className="error-text">{err}</p>}
</ErrorMessage>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
);
};
export default SimpleForm;
这样就完成了所有的实作,底下附上放在 codesandbox 上的程序码。
<<: 【Day27】React Redux 原理及应用方法简介 ╰(°ㅂ°)╯
>>: Day13|【Git】档案管理 - 档案还原 git checkout
目标: 做出台湾加权指数 K 线图 之前做出来的台股申购是独立的功能,为了不影响前面已经完成的功能,...
Redis Request Routing 在Redis Server丛集中所有的操作透过Reque...
What is Flexbox? Flexbox = Flexible Box "CSS3...
Show the browser's Elements and Network tool insi...
程序开发的过程很难不接触到终端机操作,原生的画面非常"简约",透过套件强化後不只...