概述

让我们面对现实吧,React 中的表单确实非常冗长。更糟糕的是,大多数表单助手做了太多的魔法,并且通常会带来显着的性能成本。Formik 是一个小型库,可以帮助你解决 3 个最烦人的部分:

¥Let's face it, forms are really verbose in React. To make matters worse, most form helpers do wayyyy too much magic and often have a significant performance cost associated with them. Formik is a small library that helps you with the 3 most annoying parts:

  1. 从表单状态获取值和从表单状态获取值

    ¥Getting values in and out of form state

  2. 验证和错误消息

    ¥Validation and error messages

  3. 处理表单提交

    ¥Handling form submission

通过将上述所有内容集中在一个地方,Formik 将使事情井井有条 - 使测试、重构和推断表单变得轻而易举。

¥By colocating all of the above in one place, Formik will keep things organized--making testing, refactoring, and reasoning about your forms a breeze.

动机

¥Motivation

我(@jaredpalmer)在使用 @eonwhite 构建大型内部管理仪表板时编写了 Formik。有了大约 30 种独特的表单,我们很快就发现,我们不仅可以通过标准化我们的输入组件,还可以通过标准化数据在表单中流动的方式而受益。

¥I (@jaredpalmer) wrote Formik while building a large internal administrative dashboard with @eonwhite. With around ~30 unique forms, it quickly became obvious that we could benefit by standardizing not just our input components but also the way in which data flowed through our forms.

为什么不使用 Redux-Form 呢?

¥Why not Redux-Form?

现在,你可能会想,“为什么不直接使用 Redux 形式 呢?” 好问题。

¥By now, you might be thinking, "Why didn't you just use Redux-Form?" Good question.

  1. 根据我们的先知丹·阿布拉莫夫 (Dan Abramov) 的说法,表单状态本质上是短暂的和本地的,因此没有必要在 Redux(或任何类型的 Flux 库)中跟踪它

    ¥According to our prophet Dan Abramov, form state is inherently ephemeral and local, so tracking it in Redux (or any kind of Flux library) is unnecessary

  2. Redux-Form 在每次按键时都会多次调用整个顶层 Redux reducer。这对于小型应用来说很好,但是随着你的 Redux 应用的增长,如果你使用 Redux-Form,输入延迟将继续增加。

    ¥Redux-Form calls your entire top-level Redux reducer multiple times ON EVERY SINGLE KEYSTROKE. This is fine for small apps, but as your Redux app grows, input latency will continue to increase if you use Redux-Form.

  3. Redux-Form 压缩压缩后大小为 22.5 kB(Formik 为 12.7 kB)

    ¥Redux-Form is 22.5 kB minified gzipped (Formik is 12.7 kB)

我对 Formik 的目标是创建一个可扩展、高性能的表单助手,它具有最小的 API,可以完成真正烦人的事情,剩下的就交给你了。

¥My goal with Formik was to create a scalable, performant, form helper with a minimal API that does the really really annoying stuff, and leaves the rest up to you.


我在 React Alicante 的演讲更深入地探讨了 Formik 的动机和理念,介绍了该库(通过观看我构建它的迷你版本),并演示了如何使用以下方法构建一个不平凡的表单(使用数组、自定义输入等) 真实的事情。

¥My talk at React Alicante goes much deeper into Formik's motivation and philosophy, introduces the library (by watching me build a mini version of it), and demos how to build a non-trivial form (with arrays, custom inputs, etc.) using the real thing.

https://www.youtube.com/embed/oiNtnehlaTo

影响

¥Influences

Formik 首先通过 布伦特·杰克逊这个高阶组件 上进行了扩展,Redux-Form 中的一些命名约定,以及(最近)由 反应运动React-Router 4 普及的渲染属性方法。无论你是否使用过上述任何一项,Formik 只需几分钟即可上手。

¥Formik started by expanding on this little higher order component by Brent Jackson, some naming conventions from Redux-Form, and (most recently) the render props approach popularized by React-Motion and React-Router 4. Whether you have used any of the above or not, Formik only takes a few minutes to get started with.

安装

¥Installation

你可以通过 NPMYarnunpkg.com 安装 Formik。

¥You can install Formik with NPM, Yarn, or a good ol' <script> via unpkg.com.

NPM

npm install formik --save

or

yarn add formik

Formik 与 React v15+ 兼容,并可与 ReactDOM 和 React Native 配合使用。

¥Formik is compatible with React v15+ and works with ReactDOM and React Native.

你也可以在购买前尝试一下这款 CodeSandbox.io 上的 Formik 演示

¥You can also try before you buy with this demo of Formik on CodeSandbox.io

浏览器内在线运行

¥In-browser Playgrounds

你可以在网络浏览器中通过这些实时在线运行与 Formik 一起玩。

¥You can play with Formik in your web browser with these live online playgrounds.

要旨

¥The Gist

Formik 跟踪你的表单状态,然后通过 props 将其以及一些可重用方法和事件处理程序(handleChangehandleBlurhandleSubmit)公开给你的表单。handleChangehandleBlur 完全按照预期工作 - 它们使用 nameid 属性来确定要更新哪个字段。

¥Formik keeps track of your form's state and then exposes it plus a few reusable methods and event handlers (handleChange, handleBlur, and handleSubmit) to your form via props. handleChange and handleBlur work exactly as expected--they use a name or id attribute to figure out which field to update.

import React from 'react';
import { Formik } from 'formik';
const Basic = () => (
<div>
<h1>Anywhere in your app!</h1>
<Formik
initialValues={{ email: '', password: '' }}
validate={values => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (
!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = 'Invalid email address';
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
/* and other goodies */
}) => (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
/>
{errors.email && touched.email && errors.email}
<input
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{errors.password && touched.password && errors.password}
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</form>
)}
</Formik>
</div>
);
export default Basic;

减少样板

¥Reducing boilerplate

上面的代码非常明确地说明了 Formik 正在做什么。onChange -> handleChangeonBlur -> handleBlur,依此类推。然而,为了节省你的时间,Formik 附带了一些额外的组件,使生活更轻松、更简洁:<Form /><Field /><ErrorMessage />。他们使用 React 上下文来钩子父 <Formik /> 状态/方法。

¥The code above is very explicit about exactly what Formik is doing. onChange -> handleChange, onBlur -> handleBlur, and so on. However, to save you time, Formik comes with a few extra components to make life easier and less verbose: <Form />, <Field />, and <ErrorMessage />. They use React context to hook into the parent <Formik /> state/methods.

// Render Prop
import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
const Basic = () => (
<div>
<h1>Any place in your app!</h1>
<Formik
initialValues={{ email: '', password: '' }}
validate={values => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (
!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = 'Invalid email address';
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({ isSubmitting }) => (
<Form>
<Field type="email" name="email" />
<ErrorMessage name="email" component="div" />
<Field type="password" name="password" />
<ErrorMessage name="password" component="div" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
</div>
);
export default Basic;

阅读下文了解更多信息...

¥Read below for more information...

配套包

¥Complementary Packages

正如你在上面看到的,验证由你决定。你可以随意编写自己的验证器或使用第三方库。就我个人而言,我使用 是的 进行对象模式验证。它有一个与 Joi / React PropTypes 非常相似的 API,但对于浏览器来说足够小,对于运行时使用来说足够快。因为我❤️ Yup 太多了,Formik 有一个名为 validationSchema 的特殊配置选项/属性,它会自动将 Yup 的验证错误转换为一个漂亮的对象,其密钥与 valuestouched 匹配。不管怎样,你可以从 npm 安装 Yup...

¥As you can see above, validation is left up to you. Feel free to write your own validators or use a 3rd party library. Personally, I use Yup for object schema validation. It has an API that's pretty similar to Joi / React PropTypes but is small enough for the browser and fast enough for runtime usage. Because I ❤️ Yup sooo much, Formik has a special config option / prop for Yup called validationSchema which will automatically transform Yup's validation errors into a pretty object whose keys match values and touched. Anyways, you can install Yup from npm...

npm install yup --save

or

yarn add yup
Formik 中文网 - 粤ICP备13048890号