Formik官方應用案例解析(二)同步校驗
官方示例工程formik-09x-synchronous-validation-example展示的是基於Formik的表單開發中如何進行定制的同步校驗的問題。
上一個實例相關內容回顧
回顧一下第一個示例Basics,其中有下面代碼:
const EnhancedForm = withFormik({ mapPropsToValues: () => ({ email: ‘‘ }), validationSchema: Yup.object().shape({ email: Yup.string() .email(‘Invalid email address‘) .required(‘Email is required!‘), }), handleSubmit: (values, { setSubmitting }) => { setTimeout(() => { alert(JSON.stringify(values, null, 2)); setSubmitting(false); }, 1000); }, displayName: ‘BasicForm‘, // helps with React DevTools })(MyInnerForm);
在上面代碼片斷中,理解mapPropsToValues屬性的作用對於理解Formik全局有極為重要的意義。註意,在這裏它返回了一個props對象(本例中是{ email: ‘‘ })。正是由於這一映射(即轉換操作),才有了其他對應位置接下來的values.email(即props.values.email)引用。
其次,在實現表單數據校驗方面,使用了下面代碼:
validationSchema: Yup.object().shape({ email: Yup.string() .email(‘Invalid email address‘) .required(‘Email is required!‘), }),
這個validationSchema是使用Yup這個開源JS校驗工具庫所要求的。註意到,在判斷一個字符串是否是一個有效的Email地址時,它使用了內置於Yup庫的判斷方式(調用email()方法進行判定——而並沒有使用原始的正則表達式判定方式。
【問題】這裏預留一個問題供朋友們思考:上面Yup校驗是同步的還是異步的?
定制的表單同步校驗
本文案例給出的正是Formik支持下的表單同步校驗支持方案。關鍵代碼如下:
const MyEnhancedForm = withFormik({ mapPropsToValues: () => ({ email: ‘‘ }), // Custom sync validation validate: values => { let 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; }, handleSubmit: (values, { setSubmitting }) => { setTimeout(() => { alert(JSON.stringify(values, null, 2)); setSubmitting(false); }, 1000); }, displayName: ‘BasicForm‘, // helps with React DevTools })(MyForm);
其實,這裏關鍵是理解validate這個屬性(withFormik()方法的參數是一個可配置對象,validate則是該對象的屬性之一)。根據官方文件介紹,這個屬性是實現定制同步校驗編程的關鍵思路。而且註意到,上面代碼中使用非常原始的正則表達式方案校驗電子郵件地址格式正確與否。
如果把這裏的思路放開一些,即可以通過判定values.email,values.someotherfield......來進行其他眾多的字段內容校驗判定。也就是由於這一思路,我們註意到沒有必要再和redux-form中那樣實現專門的字段級別校驗了。
異步校驗
盡管官方沒有給出完整獨立的表單異步校驗案例,但是官方文檔再介紹withFormik的validate屬性用法時一並提供了同步校驗和異步校驗的例子,不過都是使用了定制校驗方式:
// Synchronous validation
const validate = (values, props) => {
let 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;
};
// Async Validation
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const validate = (values, props) => {
return sleep(2000).then(() => {
let errors = {};
if ([‘admin‘, ‘null‘, ‘god‘].includes(values.username)) {
errors.username = ‘Nice try‘;
}
// ...
if (Object.keys(errors).length) {
throw errors;
}
});
};
其實,Formik作者極力推薦的Yup方案(結合validationSchema的使用)就是一種極其簡潔的異步校驗方案。當然,示例Basics中的代碼比較隱蔽;更直觀的異步校驗代碼片段如下:
const numSchema = yup.number();
const validator = (val) => {
numSchema.validate(val)
.then(result => {
console.log(result); // it is the value of `val`
return true;
})
.catch(error => {
console.log(error.errors); // array of validation error messages
return false;
});
};
相信你能夠輕松地把上面代碼片段修改後添加到withFormik這個HOC函數代碼當中。
引用
1,著名開源JS校驗工具Yup(https://github.com/jquense/yup);
2,https://github.com/jaredpalmer/formik#validationschema-schema--props-props--schema
3,https://til.hashrocket.com/posts/35a5bwlxn7-yup-schemas-are-validated-asynchronously
Formik官方應用案例解析(二)同步校驗