設(shè)想你要開發(fā)一個可以編輯用戶數(shù)據(jù)的表單。不過,你的用戶API端使用了具有類似下面的嵌套對象表達:
從網(wǎng)站建設(shè)到定制行業(yè)解決方案,為提供成都網(wǎng)站制作、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)服務(wù)體系,各種行業(yè)企業(yè)客戶提供網(wǎng)站建設(shè)解決方案,助力業(yè)務(wù)快速發(fā)展。創(chuàng)新互聯(lián)將不斷加快創(chuàng)新步伐,提供優(yōu)質(zhì)的建站服務(wù)。
{
id: string,
email: string,
social: {
facebook: string,
twitter: string,
// ...
}
}
最后,我們想使開發(fā)的對話框表單能夠接收下面幾個屬性(props):user,updateUser和onClose(顯然,user是一個對象,updateUser和onClose卻都是兩個方法)。
// User.js
import React from 'react';
import Dialog from 'MySuperDialog';
import { Formik } from 'formik';
const EditUserDialog = ({ user, updateUser, onClose }) => {
return (
);
};
為了簡化表單組件的編碼,F(xiàn)ormik還提供了兩個幫助API:
于是,下面的代碼與前面一致,只是使用
和// EditUserDialog.js
import React from 'react';
import Dialog from 'MySuperDialog';
import { Formik, Field, Form } from 'formik';
const EditUserDialog = ({ user, updateUser, onClose }) => {
return (
);
};
Formik與React Native 和React Native Web開發(fā)完全兼容。然而,由于ReactDOM和React Native表單處理與文本輸入方式的不同,有兩個區(qū)別值得注意。本文將介紹這個問題并推薦更佳使用方式。
在進一步討論前,先來最簡要地概括一下如何在React Native中使用Formik。下面的輪廓代碼展示了兩者的關(guān)鍵區(qū)別:
// Formik +React Native示例
import React from 'react';
import { Button, TextInput, View } from 'react-native';
import { withFormik } from 'formik';
const enhancer = withFormik({
/*...*/
});
const MyReactNativeForm = props => (
);
export default enhancer(MyReactNativeForm);
從上面代碼中,你會明顯注意到在React Native 和React DOM開發(fā)中使用Formik存在如下不同:
(1)Formik的props.handleSubmit被傳遞給一個,而不是HTML
組件(因為在React Native中沒有元素)。(2)
如果因某種原因你想在每一個render中避免創(chuàng)建新函數(shù),那么我建議你把React Native的
請參考下面的代碼:
// FormikReactNativeTextInput.js
import * as React from 'react';
import { TextInput } from 'react-native';
export default class FormikReactNativeTextInput extends React.Component {
handleChange = (value: string) => {
// remember that onChangeText will be Formik's setFieldValue
this.props.onChangeText(this.props.name, value);
};
render() {
// we want to pass through all the props except for onChangeText
const { onChangeText, ...otherProps } = this.props;
return (
);
}
}
然后,你可以像下面這樣使用這個定制輸入組件:
// MyReactNativeForm.js
import { View, Button } from 'react-native';
import TextInput from './FormikReactNativeTextInput';
import { Formik } from 'formik';
const MyReactNativeForm = props => (
{
setTimeout(() => {
console.log(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
render={props => (
)}
/>
);
export default MyReactNativeForm;
Formik是使用TypeScript寫的,F(xiàn)ormik中的類型十分類似于React Router 4中的
Render props ( and )
import * as React from 'react';
import { Formik, FormikProps, Form, Field, FieldProps } from 'formik';
interface MyFormValues {
firstName: string;
}
export const MyApp: React.SFC<{} /* whatever */> = () => {
return (
My Example
alert(JSON.stringify(values))}
render={(formikBag: FormikProps) => (
)}
/>
);
};
import React from 'react';
import * as Yup from 'yup';
import { withFormik, FormikProps, FormikErrors, Form, Field } from 'formik';
// Shape of form values
interface FormValues {
email: string;
password: string;
}
interface OtherProps {
message: string;
}
順便提醒一下,你可以使用InjectedFormikProps
const InnerForm = (props: OtherProps & FormikProps) => {
const { touched, errors, isSubmitting, message } = props;
return (
);
};
//MyForm接收的props的類型
interface MyFormProps {
initialEmail?: string;
message: string; // if this passed all the way through you might do this or make a union type
}
//使用withFormik高階組件包裝你的表單
const MyForm = withFormik({
// Transform outer props into form values
mapPropsToValues: props => {
return {
email: props.initialEmail || '',
password: '',
};
},
//添加定制的校驗函數(shù)(也有可能是異步的)
validate: (values: FormValues) => {
let errors: FormikErrors = {};
if (!values.email) {
errors.email = 'Required';
} else if (!isValidEmail(values.email)) {
errors.email = 'Invalid email address';
}
return errors;
},
handleSubmit: values => {
// do submitting things
},
})(InnerForm);
// 你可以在任何地方使用
const Basic = () => (
My App
This can be anywhere in your application
);
export default Basic;
要在Formik中提交表單,你需要以某種方式觸發(fā) handleSubmit(e) 或者submitForm屬性調(diào)用(在Formik中這兩個方法都是以屬性的方式提供的)。 當調(diào)用其中一個方法時,F(xiàn)ormik每次都會執(zhí)行下面的偽代碼:
(一)預提交
(1)修改所有字段
(2)把isSubmitting 設(shè)置為true
(3)submitCount + 1
(二)校驗
(1)把isValidating設(shè)置為true
(2)異步運行所有字段級的校驗和validationSchema,并深度合并執(zhí)行結(jié)果
(3)判斷是否存在錯誤:
如果存在錯誤:取消提交,把isValidating設(shè)置為false,設(shè)置錯誤信息,并把isSubmitting設(shè)置為false
如果不存在錯誤:Set isValidating to false, proceed to "Submission"
(三)提交
最后繼續(xù)運行你的提交函數(shù)吧(例如是onSubmit或者handleSubmit)。你可以通過在你的處理器函數(shù)中調(diào)用setSubmitting(false) 來結(jié)束生命周期。
(1)Q:怎么判定提交處理器(submission handler)正在執(zhí)行中?
A:當isValidating為false且isSubmitting為true時。
(2)Q:為什么在提交前Formik要“潤色一下(touch)”表單中所有字段?
A:通常,當UI表單中輸入字段被操作過后(Formik中稱為“touched”)只顯示與之相關(guān)的錯誤信息。于是,在提交一個表單前,F(xiàn)ormik會touch一下所有字段,這樣所有可能隱藏的錯誤都會變得可見。
(3)Q:如何避免兩次重復提交?
A:辦法是當isSubmitting為true時,禁止所有能夠觸發(fā)提交的調(diào)用。
(4)Q:如何得知表單在提交前正在校驗中?
A:如果isValidating為true而且isSubmitting也為true的話,......