本文主要用於記錄該次使用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