本文主要用于记录该次使用Formik时用到的相关接口,而侧重点不在antd-mobile,对antd-mobile会贴出对应组件API。react
文章须要基础知识点:git
文章实践环境为:github
文章最后成果:redux
开源的轻量级 React 表单组件。
GitHub地址:Formik
该表单组件主要解决如下三个问题:antd
至于为何不用 redux-form 做者也给出了解释:app
ant-design的移动版UI组件库。
官网:antd-mobile
不须要多作介绍了,每一个写React的人都应该据说或用过antd系列的UI组件库吧。异步
withFormik()
HOC方法<Formik />
React组件二者使用内在实际上是相同,在可控性上React组件方式会更好,对此能够不须要太在乎,你能够随时在两种使用方法间作转换。
本文上篇主要讲述Formik的HOC方法下的基本封装,下篇则侧重于封装经常使用组件并对Formik两种使用方法的切换作一次简单的总结。async
// Higher Order Component import React from 'react'; import { withFormik } from 'formik'; // Our inner form component which receives our form's state and updater methods as props // 这就是个组件,传入的props是由withFormik这个HOC函数内部作处理。 const InnerForm = ({ values, // 表单中的值,为一个对象{} errors, // 用于报错提示的信息,为一个对象{} touched, // 用于检查用户是否点击过该表单项,为一个对象{} handleChange, /* handleChange:默认的值修改回调函数,传入参数为 e: React.ChangeEvent<any> 对象。 因此若是使用antd-mobile组件,因为某些组件传入参数为 value 值,所以须要对此进行必定程度上的封装*/ handleBlur, /* handleBlur:失去焦点时默认的回调函数,传入参数为 event 对象。 须要自定义时也须要对应的封装。这个函数和handleChange都是DOM-only的函数 */ handleSubmit, // 传入参数为 e: React.FormEvent<HTMLFormEvent> 对象 isSubmitting, // isSubmitting表示表单提交的状态 }) => ( <form onSubmit={handleSubmit}> <input type="email" name="email" onChange={handleChange} onBlur={handleBlur} value={values.email} /> // 判断该项 被点击过、具备错误信息 的状况下,显示错误消息<div>{errors.email}</div>。 {touched.email && errors.email && <div>{errors.email}</div>} <input type="password" name="password" onChange={handleChange} onBlur={handleBlur} value={values.password} /> {touched.password && errors.password && <div>{errors.password}</div>} <button type="submit" disabled={isSubmitting}> Submit </button> </form> ); // Wrap our form with the using withFormik HoC // 具体参数能够看这里 const MyForm = withFormik({ // Transform outer props into form values // 将外部传入props设为表单的值,如 email: props.email 就可设置表单的值 mapPropsToValues: props => ({ email: '', password: '' }), // Add a custom validation function (this can be async too!) // 在submit前会调用该函数对值进行检查,若是errors为{}则会执行handleSubmit validate: (values, props) => { const errors = {}; if (!values.email) { errors.email = 'Required'; } else if ( !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email) ) { errors.email = 'Invalid email address'; } return errors; }, // Submission handler // 传入参数为表单提交时的值与一个FormikBag对象,该对象具备传入的props和method,具体能够查看对应文档描述 handleSubmit: ( values, { props, setSubmitting, setErrors /* setValues, setStatus, and other goodies */, } ) => { // 具体submit后执行函数,LoginToMyApp没必要过多关心。 // 示例就是进行了一个异步请求并对返回的结果作处理。 LoginToMyApp(values).then( user => { setSubmitting(false); // do whatevs... // props.updateUser(user) }, errors => { setSubmitting(false); // Maybe even transform your API's errors into the same shape as Formik's! setErrors(transformMyApiErrors(errors)); } ); }, })(InnerForm); // Use <MyForm /> anywhere const Basic = () => ( <div> <h1>My Form</h1> <p>This can be anywhere in your application</p> <MyForm /> </div> ); export default Basic;
官方示例的使用方法比较清晰,咱们在该基础上逐步修改便可。函数
示例中,咱们能够看出主要须要掌握的不多,const InnerForm
仅仅是一个无状态组件。const MyForm
是经过HOC方法返回的一个表单组件。ui
const InnerForm = ({ values, errors, touched, handleBlur, handleChange, handleSubmit, isSubmitting }) => (<form></form>)
其中前三项values为表单值、errors为错误记录、touched为是否点击过对应表单记录。
而handleBlur和handleChange都是DOM-only的回调函数,接受传入参数为 Event 对象,若是咱们在表单中使用第三方组件,则须要用到另外两个方法。
其中第三个参数是设置是否跳过验证。
再看
const MyForm = withFormik({ mapPropsToValues, validate, handleSubmit })
经过HOC方法,实现了对InnerForm
表单设置默认值、表单值验证、表单提交三个方法。
FormikBag
对象属性:
props
resetForm
setErrors
setFieldError
setFieldTouched
setFieldValue
setStatus
setSubmitting
setTouched
setValues
值得注意的是,FormikBag
不包含全部事件处理函数与errors,status,touched
,FormikBag
提供的是在表单submit后,对表单的处理所需的函数,好比经过setFieldError函数,提供如 用户名重复
之类的错误信息。
从上一步能够得知,咱们主要的渲染部分放在了InnerForm
组件中,因此此次咱们把目光放在InnerForm组件中便可。
该步骤使用到的antd-mobile组件为:
首先写入InnerForm
组件中咱们须要的参数和基本骨架:
const InnerForm = ({ values, errors, touched, handleBlur, setFieldTouched, setFieldValue, handleSubmit, isSubmitting }) => (<form onSubmit={handleSubmit}> <WingBlank> <List> </List> </WingBlank> </form>)
接下来咱们添加一个输入框用于接收用户输入的email地址。
在<List></List>
中插入InputItem
组件以下:
<List> <InputItem onChange={(value)=>setFieldValue('email',value)} onBlur={()=>{setFieldTouched('email',true)}} value={values.email} touched={touched.email} errors={errors.email} /> </List>
这里值得注意,首先咱们看看InputItem组件的文档,onChange
和onBlur
的默认参数都是string
,而不是Event
对象,在这里咱们须要弃用官方文档中的handleBlur
和handleChange
两个回调参数,手动的调用setFieldValue
和setFieldTouched
来完成相应的效果。
若是使用官方文档使用的
{touched.password && errors.password && <div>{errors.password}</div>}
进行错误提醒,那么重复的代码工做量会略大了,在这里咱们把错误提示作成一个组件。
具体代码以下:
const MyErrorItem = props => props.touched && props.errors ? ( <List.Item style={{ backgroundColor: "#eee" }}> <span style={{ color: "red", fontSize: ".7rem"}}>* {props.errors}</span> </List.Item> ) : null;
那么错误提醒的代码就缩减成了
<MyErrorItem touched={touched.password} errors={errors.password} />
再次经过HOC咱们能够将整个InputItem
组件与MyErrorItem
组件组合在一块儿。
function HOCErrorInItem(NormalComponent, ErrorComponent) { return class HOCErrorFormItem extends React.Component { render(){ return (<div> <NormalComponent {...this.props} /> <ErrorComponent touched={this.props.touched} errors={this.props.errors} /> </div>) } } } const MyInputItem = props =>( <InputItem type={props.type} name={props.name} onChange={value => props.onChange(value)} onBlur={props.onBlur} value={props.value} > {props.label} </InputItem> ) const InputItemWithErrorTip = HOCErrorInItem(MyInputItem,MyErrorItem)
这样咱们须要就封装好了一个附带错误提示的输入框组件。
到这一步,咱们的InnerForm
组件应该以下:
const InnerForm = ({ values, errors, touched, handleBlur, setFieldTouched, setFieldValue, handleSubmit, isSubmitting }) => (<form onSubmit={handleSubmit}> <WingBlank> <List> <InputItemWithErrorTip type="email" name="Email" label="Email" onChange={value => setFieldValue("email", value)} onBlur={()=>{setFieldTouched('email',true)}} value={value.email} touched={touched.email} errors={errors.email} /> </List> </WingBlank> </form>)
该文上篇到此结束,此次主要是工做时候做为记录而言描写如下本身的思路,毕竟好记性不如烂笔头,也算是简单梳理一下思路。
具体补充将在下篇完成,内容应该包括各种型表单组件封装,工做完成后对封装组件的反思,下篇完成时间尽可能在9月中完成,目前代码仍然处于封装各个组件的阶段。
动笔时间也与上次相比相隔甚久了,感受本身仍是摸索路上,趁着工做压力不大,多看多读多想多写吧。
=_=天天动工一点点,优先知足工做须要。
欢迎你们的一切快乐讨论。
目前施工现场:
CodeSandBox
Github