弁言
看過antd源碼的都曉得,antd實際上是在一組react-componment組件的基本上舉行了一層ui封裝,本文重要解讀antd組件Form的基本組件react-componment/form,別的會略過development
形式下的warning代碼。
Form.create
解讀源碼起首要從本身最經常運用的或許感興趣的入手,起首form組件最重要的照樣在Form.create({options})
這個裝潢器入手。找到項面前目今的文件createForm.js
,這個文件照樣重要重要對createBaseForm.js
文件舉行了一層封裝,供應了一些默許設置參數,下看檢察createBaseForm.js
里的createBaseForm要領,改要領重假如一個裝潢器作用,包裝一個高階React組件,在props里注入一個值為formPropName(默許為form)
變量,一切功用在這個變量里完成,重要內容以下
render() {
const { wrappedComponentRef, ...restProps } = this.props;
const formProps = {
[formPropName]: this.getForm(), // 來在 formPropName默許為form,getForm要領來自`createForm.js`
};
if (withRef) {
formProps.ref = 'wrappedComponent';
} else if (wrappedComponentRef) {
formProps.ref = wrappedComponentRef;
}
const props = mapProps.call(this, {
...formProps,
...restProps,
});
return <WrappedComponent {...props} />;
}
在裝潢器初始化的時刻,Form初始化了一個只屬於該組件實例的store,用來寄存當前Form組件的一些輸入的數據,重要代碼以下:
const fields = mapPropsToFields && mapPropsToFields(this.props); // mapPropsToFields來自於Form.create的設置參數,用來轉化來自mobx或許redux等真正的store泉源的value,以初始化該Form實例的fieldsStore
this.fieldsStore = createFieldsStore(fields || {}); // createFieldsStore來自於文件`createFieldsStore.js`文件
getFieldDecorator
柯里化函數,經由過程id與參數聲明的輸入,返回一個函數以輸入組件為入參的函數,經由過程該函數聲明的輸入組件與表單Form雙向數據綁定。
...
getFieldDecorator(name, fieldOption) {
const props = this.getFieldProps(name, fieldOption); // 初始化一個field
return (fieldElem) => {
const fieldMeta = this.fieldsStore.getFieldMeta(name); // 獵取變化(Form的onChange)后的field數據
const originalProps = fieldElem.props;
fieldMeta.originalProps = originalProps; // 輸入組件初始化時保留的Prop
fieldMeta.ref = fieldElem.ref;
return React.cloneElement(fieldElem, {
...props,
...this.fieldsStore.getFieldValuePropValue(fieldMeta), // 獵取prop屬性 value
});
};
}
...
getFieldProps
檢察函數 getFieldProps
,重要用來初始化輸入組件的props,將特定的函數緩存在內部,如onChange事宜,別的首次保留field到store中
...
getFieldProps(name, usersFieldOption = {}) {
if (!name) {
throw new Error('Must call `getFieldProps` with valid name string!');
}
delete this.clearedFieldMetaCache[name];
const fieldOption = {
name,
trigger: DEFAULT_TRIGGER,
valuePropName: 'value',
validate: [],
...usersFieldOption, // 用戶輸入,如rules,initialValue
};
const {
rules,
trigger,
validateTrigger = trigger,
validate,
} = fieldOption;
const fieldMeta = this.fieldsStore.getFieldMeta(name);
if ('initialValue' in fieldOption) {
fieldMeta.initialValue = fieldOption.initialValue;
}
const inputProps = {
...this.fieldsStore.getFieldValuePropValue(fieldOption), // 獵取輸入組件的value,假如沒有,返回initialValue
ref: this.getCacheBind(name, `${name}__ref`, this.saveRef),
};
if (fieldNameProp) { // 及value
inputProps[fieldNameProp] = name;
}
const validateRules = normalizeValidateRules(validate, rules, validateTrigger); // 校驗劃定規矩標準化
const validateTriggers = getValidateTriggers(validateRules);
validateTriggers.forEach((action) => {
if (inputProps[action]) return;
inputProps[action] = this.getCacheBind(name, action, this.onCollectValidate); // 假如設置了輸入校驗rules,綁定onChange事宜`this.onCollectValidate`
});
// make sure that the value will be collect
if (trigger && validateTriggers.indexOf(trigger) === -1) {
inputProps[trigger] = this.getCacheBind(name, trigger, this.onCollect); // 假如沒有綁定rules校驗,綁定默許的onChange事宜
}
const meta = {
...fieldMeta,
...fieldOption,
validate: validateRules,
};
this.fieldsStore.setFieldMeta(name, meta); // 保留field到store中
if (fieldMetaProp) {
inputProps[fieldMetaProp] = meta;
}
if (fieldDataProp) {
inputProps[fieldDataProp] = this.fieldsStore.getField(name);
}
return inputProps;
},
...
getCacheBind
getCacheBind
要領,緩存函數,運用bind要領綁定上下文並緩存部份參數,返回一個新的函數,用做onChange及數據校驗。
...
getCacheBind(name, action, fn) {
if (!this.cachedBind[name]) {
this.cachedBind[name] = {};
}
const cache = this.cachedBind[name];
if (!cache[action]) {
cache[action] = fn.bind(this, name, action); // 綁定參數並返回
}
return cache[action];
},
...
onCollectCommon
在getFieldProps
要領中看到應用getCacheBind
要領當無rules的時刻綁定了一個onCollect
要領,onCollect要領重要挪用onCollectCommon
要領,並將獲得的效果保留到store。
onCollectCommon(name, action, args) {
const fieldMeta = this.fieldsStore.getFieldMeta(name);
if (fieldMeta[action]) { // 假如getFieldDecorator要領中的參數定義了onChange,則觸發改onChange
fieldMeta[action](...args);
} else if (fieldMeta.originalProps && fieldMeta.originalProps[action]) { // 假如輸入組件綁定了onChange,則觸發該onChange
fieldMeta.originalProps[action](...args);
}
const value = fieldMeta.getValueFromEvent ? // 獵取更新后的value,兼容原生組件e.target.value
fieldMeta.getValueFromEvent(...args) :
getValueFromEvent(...args);
if (onValuesChange && value !== this.fieldsStore.getFieldValue(name)) { // 假如Form.create時用戶定義有onValuesChange,則觸發
const valuesAll = this.fieldsStore.getAllValues();
const valuesAllSet = {};
valuesAll[name] = value;
Object.keys(valuesAll).forEach(key => set(valuesAllSet, key, valuesAll[key]));
onValuesChange(this.props, set({}, name, value), valuesAllSet);
}
const field = this.fieldsStore.getField(name); // 獵取兼并field,並返回
return ({ name, field: { ...field, value, touched: true }, fieldMeta });
},
onCollectValidate
在有輸入rules的時刻getCacheBind
要領綁定onCollectValidate
作為onChange事宜,該要領做了除了挪用了onCollectCommon事宜之外,還挪用了校驗要領validateFieldsInternal
。
validateFieldsInternal
該要領重假如從store中獵取rules校驗劃定規矩並標準化后,運用async-validator
模塊舉行校驗,並把效果保留到store中,本文不做解說。
setFields
該要領重假如設置store中的field,由於store的數據是不可觀察的數據,不會引發頁面的重襯着,該要領也擔任挪用forceUpdate()
強迫更新頁面。
setFields(maybeNestedFields, callback) {
const fields = this.fieldsStore.flattenRegisteredFields(maybeNestedFields); // 處置懲罰field嵌套題目
this.fieldsStore.setFields(fields);
if (onFieldsChange) { // 假如設置有FieldsChange事宜監聽事宜變化,則觸發事宜
const changedFields = Object.keys(fields)
.reduce((acc, name) => set(acc, name, this.fieldsStore.getField(name)), {});
onFieldsChange(this.props, changedFields, this.fieldsStore.getNestedAllFields());
}
this.forceUpdate(callback); // 強迫更新視圖
},
末了
重要要領也許就上面這些,个中流程差不多在每次setFields之前,會在store中存一個field的變化字段fieldMeta
,在末了強迫更新頁面的時刻,將該變量取出來做處置懲罰后掩蓋到field,一切數據保留在field中,並供應了一些hock要領如setFieldsValue
、validateFields
等要領設置和獵取store中的field字段和值。