十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Formik 总览:用最小 API 在 React 中构建表单的状态、校验与提交

Formik 总览:用最小 API 在 React 中构建表单的状态、校验与提交 Formik 总览用最小 API 在 React 中构建表单的状态、校验与提交【免费下载链接】formikBuild forms in React, without the tears 项目地址: https://gitcode.com/gh_mirrors/fo/formik表单在 React 中一向以啰嗦著称而 Formik 正是为了解决获取/写入表单状态、校验与错误提示、处理提交这三大痛点而生的轻量级表单库。本篇文章基于本仓库 docs/overview.md 展开并结合 packages/formik/src 下的核心源码帮助你理解 Formik 的诞生动机、设计哲学、安装方式、核心工作流The Gist、样板代码的削减方案以及 Yup 校验集成读完后你既能快速上手也能从源码层面理解它为什么这样设计。一、核心问题为什么 React 表单如此繁琐在纯 React 中编写表单你需要手工完成大量重复劳动为每个输入框维护独立的value与onChange把错误信息存进组件局部 state再在提交时逐个读取和校验字段。正如 docs/overview.md 开篇所说表单在 React 里非常啰嗦really verbose而多数表单辅助库又引入了过多的魔法magic并常常伴随显著的性能开销。Formik 是一个小型库它只帮你解决以下三个最令人头疼的问题状态读写把值写入表单状态、从表单状态取出值Getting values in and out of form state校验与错误消息统一管理校验逻辑与错误提示Validation and error messages表单提交处理提交流程中的提交中、提交失败等状态Handling form submission。Formik 的核心思路是把上述三件事聚合到同一个地方By colocating all of the above in one place从而让表单保持组织有序使测试、重构和推理reasoning表单逻辑都变得轻松。二、动机Formik 从真实项目中走来作者 Jared Palmerjaredpalmer在构建一个包含约 30 个独特表单的大型内部管理后台admin dashboard时与 Ian Whiteeonwhite一起编写了 Formik。随着表单数量的增加他们很快意识到不仅输入组件可以标准化数据在表单中的流动方式同样值得标准化。Formik 正是这种组件复用 数据流统一需求的产物。这也解释了 Formik 的定位用最小 API 创建一个可扩展、高性能的表单辅助库帮你处理真正烦人的事情其余交给开发者自己原文见 docs/overview.md 的 Motivation 一节。它不做超出表单范畴的事把选择权留给使用者。三、为什么不用 Redux-Form作者在文档中直接回应了为什么不直接使用 Redux-Form的质疑理由有三点表单状态本质上是瞬时且局部的form state is inherently ephemeral and local。Dan Abramov 曾明确指出把这类状态放进 Redux或任何 Flux 库是不必要的性能问题Redux-Form 会在每一次按键时多次调用你的顶层 Redux reducer。在小应用中这没有问题但随着 Redux 应用规模增长使用 Redux-Form 时输入延迟会持续增加体积对比Redux-Form 压缩后约22.5 kBgzip而 Formik 约12.7 kB数据均引自 docs/overview.md 原文为文档撰写时的对比口径。基于以上原因Formik 选择把表单状态管理在组件本地通过 React Context 向下传递而不是放进全局 store。从当前仓库源码看Formik 的状态管理确实完全依赖 React 自身的机制——packages/formik/src/FormikContext.tsx 通过React.createContext创建FormikContext并导出FormikProvider/FormikConsumer以及useFormikContext钩子状态更新则由 packages/formik/src/Formik.tsx 中的formikReducer以 reducer 形式集中处理如SET_VALUES、SET_TOUCHED、SET_ERRORS、SUBMIT_ATTEMPT、SUBMIT_FAILURE、SUBMIT_SUCCESS等消息类型整个过程不需要依赖 Redux 等外部状态库。四、设计影响来源Formik 的诞生吸收了多个开源项目的思想详见 docs/overview.md 的 Influences 一节起步于 Brent Jackson 的一个小型高阶组件withForm.js来自 rebass-recomposed 项目命名约定部分借鉴了 Redux-Form最近期的设计则受到render props模式的启发这一模式由 React-Motion 和 React-Router 4 推广。无论你是否用过上述库文档明确承诺Formik 只需要几分钟就能上手。五、安装与运行环境Formik 可通过 npm 或 Yarn 安装也可以用script方式通过 unpkg 引入npm install formik --save或yarn add formik关于运行环境docs/overview.md 原文说明 Formik 兼容 React v15可用于 ReactDOM 和 React Native。需要说明的是当前仓库 packages/formik/package.json 中声明的peerDependencies为react: 16.8.0对应仓库内 Formik 2.4.9 版本这是因为新版本源码大量使用了 hooks如useFormikContext、useField如果你使用较新的 Formik 版本请以16.8.0作为 React 版本的下限参考。仓库还提供了浏览器端在线试玩入口CodeSandbox 的 ReactDOM 示例与 Snack 的 React Native 示例便于先体验再集成。在仓库 examples 目录下可以找到可直接运行的示例项目例如 examples/basic/index.js 就是一个完整的注册表单 demo展示了FormikFieldForm的基本组合examples目录还包含 async-submission、checkboxes、field-arrays、with-material-ui 等更多场景。六、The GistFormik 的核心工作方式6.1 核心机制Formik 的核心机制可以用一句话概括它替你跟踪表单的状态并通过 props 把状态和若干可复用方法、事件处理器暴露给你的表单。其中最关键的事件处理器有三个handleChange处理输入变化handleBlur处理字段失焦handleSubmit处理表单提交。handleChange和handleBlur的行为完全符合直觉——它们通过输入的name或id属性来定位要更新的字段因此你不需要为每个输入框单独编写 onChange 逻辑。从源码看这一机制在 packages/formik/src/Formik.tsx 的useFormik钩子中实现其默认行为包括validateOnChange true、validateOnBlur true、validateOnMount false、enableReinitialize false等。也就是说默认情况下字段值变化与失焦时都会触发校验而表单挂载时不会自动校验。6.2 最基础的 render props 示例下面这段来自 docs/overview.md 的示例非常直白地展示了 Formik 在做什么——每一个映射关系都清晰可见onChange→handleChangeonBlur→handleBlur提交 →handleSubmitimport React from react; import { Formik } from formik; const Basic () ( div h1Anywhere 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 typeemail nameemail onChange{handleChange} onBlur{handleBlur} value{values.email} / {errors.email touched.email errors.email} input typepassword namepassword onChange{handleChange} onBlur{handleBlur} value{values.password} / {errors.password touched.password errors.password} button typesubmit disabled{isSubmitting} Submit /button /form )} /Formik /div ); export default Basic;这段代码有几个值得注意的实战细节initialValues是必填的初始状态表单的所有字段都以它为起点validate是自定义校验函数接收当前values返回一个 errors 对象键与字段名一一对应无错误时返回空对象onSubmit接收(values, formikBag)其中setSubmitting(false)必须在异步任务结束后手动调用否则按钮会一直处于禁用状态错误展示的经典写法errors.email touched.email errors.email只在字段被触碰过blur 或提交过之后才显示错误避免用户刚打开表单就看到满屏红色警告isSubmitting用于提交期间禁用按钮配合setSubmitting形成完整的提交状态闭环。七、减少样板代码Form /、Field /与ErrorMessage /上面这种写法虽然直白但每个输入框都要手动绑定value、onChange、onBlur并手写错误展示逻辑依然繁琐。为此 Formik 提供了三个辅助组件Form /、Field /和ErrorMessage /。它们通过React Context自动挂钩到父级Formik /的状态与方法见 docs/overview.md 的 Reducing boilerplate 一节。7.1 简化后的示例// Render Prop import React from react; import { Formik, Form, Field, ErrorMessage } from formik; const Basic () ( div h1Any 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 typeemail nameemail / ErrorMessage nameemail componentdiv / Field typepassword namepassword / ErrorMessage namepassword componentdiv / button typesubmit disabled{isSubmitting} Submit /button /Form )} /Formik /div ); export default Basic;对比上一节的显式写法这里删掉了所有value/onChange/onBlur绑定和手写的错误条件判断代码量明显减少。7.2 源码层面三个组件如何协作在仓库源码中可以印证这三个组件的实现方式与协作关系Form /packages/formik/src/Form.tsx本质上是一个普通的form元素但通过useFormikContext()自动接上了handleSubmit与handleReset并默认把action设为#为兼容 iOS 输入行为防止preventDefault失败时导致页面跳转。Field /packages/formik/src/Field.tsx自动完成字段注册registerField/unregisterField用于字段级校验和 props 绑定。它还支持as/component/render/children等多种渲染方式既可以渲染原生input也可以渲染自定义组件。ErrorMessage /packages/formik/src/ErrorMessage.tsx通过connect()连接到 Formik 上下文只有当字段**既被触碰touched又存在错误error**时才渲染错误消息并支持component、render、children三种输出形式。其中connect()packages/formik/src/connect.tsx是一个通用高阶组件它读取FormikConsumerContext Consumer把整个formik上下文以formikprop 注入到目标组件并用hoist-non-react-statics保留静态属性——ErrorMessage、FastField等都是基于它构建的。这套Context render props/HOC的组合正是 docs/overview.md 中所说的React context 挂钩的源码级实现。关于Formik的完整 APIvalues、touched、errors、handleChange、handleBlur、handleSubmit、setFieldValue、setFieldTouched等可以进一步阅读 docs/api/formik.mdForm /、Field /、ErrorMessage /各自的详细文档分别在 docs/api/form.md、docs/api/field.md 和 docs/api/errormessage.md。八、校验交给谁Yup 与validationSchema上面的示例展示了validate函数式校验但文档明确指出校验完全由你自己决定你可以编写自定义校验器也可以使用第三方库。作者个人偏好使用 Yup 做对象模式校验schema validation——它的 API 与 Joi、React PropTypes 相似但体积足够小、能用于浏览器端且适合运行时使用。为此Formik 为 Yup 提供了一等公民支持validationSchema配置项 / prop。它的作用是把 Yup 的校验错误自动转换成一个普通对象对象的键与values和touched的键一一对应详见 docs/api/formik.md 中关于validationSchema、values、touched的说明。安装 Yupnpm install yup --save或yarn add yup在源码层面validationSchema的处理位于 packages/formik/src/Formik.tsx 的useFormik中如runValidationSchema相关逻辑当传入validationSchema时Formik 会调用 schema 的校验方法并把结果规范化为与values同构的errors对象errors与touched的键结构保持一致因此errors.email touched.email这类判断可以无缝复用。仓库自身的测试也对 Yup 集成做了覆盖见 packages/formik/test/yupHelpers.test.ts如果你使用 TypeScript可参考 docs/guides/typescript.md 与 examples/basic-typescript 示例。九、总结与后续学习路径Formik 的设计哲学可以归纳为三句话只管三件事状态读写、校验与错误、表单提交其余交给开发者状态留在本地借助 React Context 而非全局 store规避 Redux-Form 在大型应用中的性能与合理性争议由显式到简洁先从最直白的 render props 写法理解机制再用Form /、Field /、ErrorMessage /削减样板代码按需接入 Yup 的validationSchema。在继续深入学习时建议按以下路径展开核心组件与钩子Formik /的完整 API 见 docs/api/formik.mduseFormik与useField/useFormikContext的钩子用法见 docs/api/useFormik.md、docs/api/useField.md、docs/api/useFormikContext.md高级表单场景docs/guides/arrays.md字段数组、docs/guides/validation.md校验策略、docs/api/fieldarray.mdFieldArray /多场景示例docs/examples 目录下的异步提交、依赖字段、即时反馈、Material UI 集成等示例源码深挖packages/formik/src 下的Formik.tsx、Field.tsx、Form.tsx、ErrorMessage.tsx、FormikContext.tsx、connect.tsx与FastField.tsx以及 packages/formik/test 中的配套测试。掌握了总览中的这些核心概念你就能顺畅阅读仓库中的其余 API 文档并开始在你的 React 应用中构建第一个 Formik 表单。【免费下载链接】formikBuild forms in React, without the tears 项目地址: https://gitcode.com/gh_mirrors/fo/formik创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表