antd-form底层使用rc-form进行表单操作,这里主要分析rc-form流程。
- 产生一个新容器组件Form,内置getFieldDecorator等属性和方法。
- 复制被包裹组件的静态属性到新组建中。
- 执行声明周期事件,主要是: getInitialState 初始化默认的field,这里默认无
- render函数返回原始组件(被注入了Form组件的属性)。
function createBaseForm(option = {}, mixins = []) {
mixins = {
getForm() {
return {
getFieldsValue: this.fieldsStore.getFieldsValue,
setFieldsValue: this.setFieldsValue,
getFieldDecorator: this.getFieldDecorator,
validateFields: this.validateFields,
// ...其他方法
};
}
}
return function decorate(WrappedComponent) {
const Form = createReactClass({
mixins,
// 其他内置函数
render() {
const { wrappedComponentRef, ...restProps } = this.props;
const formProps = {
[formPropName]: this.getForm(), //从mixin引入的 在createDOMForm中
};
const props = mapProps.call(this, {
...formProps,
...restProps,
});
//把form属性挂在到WrappedComponent属性上
return <WrappedComponent {...props} />;
}
});
//复制包裹组件的静态属性到Form上
return argumentContainer(Form, WrappedComponent);
};
}
- 创建表单信息到fieldsStore
- 绑定默认onChange事件
- 触发验证
- 保存结果到fieldsStore
- 返回双向数据绑定的input组件
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
)}
getFieldDecorator(name, fieldOption) {
//初始化store字段,绑定onChange事件
const props = this.getFieldProps(name, fieldOption);
//props: {value: "", ref: ƒ, onChange: ƒ}
//接收传入input
return (fieldElem) => {
// 获取原有的表单项信息,如果没有就创建一个新的。
const fieldMeta = this.fieldsStore.getFieldMeta(name);
// 克隆传入的input组件,注入新属性,包括onChange,value等
return React.cloneElement(fieldElem, {
...props,
...this.fieldsStore.getFieldValuePropValue(fieldMeta),// { value:'123' }
});
};
}
getFieldProps(name, usersFieldOption = {}) {
const fieldOption = {
name,// 自定义组件名称
trigger: DEFAULT_TRIGGER,//默认绑定 onChange事件
valuePropName: 'value', //默认值是value属性
validate: [],
...usersFieldOption,
};
const {
rules,
trigger,
validateTrigger = trigger,
validate,
} = fieldOption;
const fieldMeta = this.fieldsStore.getFieldMeta(name);
const inputProps = {
...this.fieldsStore.getFieldValuePropValue(fieldOption),
ref: this.getCacheBind(name, `${name}__ref`, this.saveRef),
};
//转换成数组格式
const validateRules = normalizeValidateRules(validate, rules, validateTrigger);
//validateRules [{"trigger":["onChange"],"rules":[{"required":true,"message":"What's your name?"}]}]
const validateTriggers = getValidateTriggers(validateRules);
validateTriggers.forEach((action) => {
if (inputProps[action]) return;
//绑定事件
inputProps[action] = this.getCacheBind(name, action, this.onCollectValidate);
});
//FieldMeta值
const meta = {
...fieldMeta,
...fieldOption,
validate: validateRules,
};
// 设置FieldMeta !!!
this.fieldsStore.setFieldMeta(name, meta);
return inputProps;
}
onCollectValidate(name_, action, ...args) {
const { field, fieldMeta } = this.onCollectCommon(name_, action, args);
const newField = {
...field,
dirty: true, // 需要验证
};
// 验证
this.validateFieldsInternal([newField], {
action,
options: {
firstFields: !!fieldMeta.validateFirst,
},
});
}
onCollectCommon(name, action, args) {
const fieldMeta = this.fieldsStore.getFieldMeta(name);
// 执行表单的onChange事件
if (fieldMeta[action]) {
fieldMeta[action](...args);
} else if (fieldMeta.originalProps && fieldMeta.originalProps[action]) {
fieldMeta.originalProps[action](...args);
}
// 获取表单中的值,默认value
const value = fieldMeta.getValueFromEvent ?
fieldMeta.getValueFromEvent(...args) :
getValueFromEvent(...args);
const field = this.fieldsStore.getField(name);
return ({ name, field: { ...field, value, touched: true }, fieldMeta });
}
validateFieldsInternal(fields, {fieldNames,action,options = {}}, callback) {
const allRules = {};
const allValues = {};
const allFields = {};
const alreadyErrors = {};
fields.forEach((field) => {
const name = field.name;
// 不需要验证逻辑
if (options.force !== true && field.dirty === false) {
if (field.errors) {
set(alreadyErrors, name, { errors: field.errors });
}
return;
}
const fieldMeta = this.fieldsStore.getFieldMeta(name);
const newField = {
...field,
};
newField.errors = undefined;
newField.validating = true; // 正在验证状态
newField.dirty = true; // 表示需要验证
allRules[name] = this.getRules(fieldMeta, action);
allValues[name] = newField.value;
allFields[name] = newField;
});
// {"name2":{"name":"name2","value":"","touched":true,"dirty":true,"validating":true}}
this.setFields(allFields);
Object.keys(allValues).forEach((f) => {
allValues[f] = this.fieldsStore.getFieldValue(f);
});
// 初始化验证,使用async-validator库
const validator = new AsyncValidator(allRules);
if (validateMessages) {
validator.messages(validateMessages);
}
//验证rule
validator.validate(allValues, options, (errors) => {
const errorsGroup = {
...alreadyErrors,
};
if (errors && errors.length) {
errors.forEach((e) => {
const fieldName = e.field;
const field = get(errorsGroup, fieldName);
if (typeof field !== 'object' || Array.isArray(field)) {
set(errorsGroup, fieldName, { errors: [] });
}
const fieldErrors = get(errorsGroup, fieldName.concat('.errors'));
fieldErrors.push(e);
});
}
const nowAllFields = {};
Object.keys(allRules).forEach((name) => {
const fieldErrors = get(errorsGroup, name);
const nowField = this.fieldsStore.getField(name);
// 验证完成
nowField.errors = fieldErrors && fieldErrors.errors;
nowField.value = allValues[name];
nowField.validating = false;
nowField.dirty = false;
nowAllFields[name] = nowField;
});
// {"name2":{"name":"name2","value":"","touched":true,"dirty":false,"errors":[{"message":"What's your name?","field":"name2"}],"validating":false}}
this.setFields(nowAllFields);
if (callback) {
callback(isEmptyObject(errorsGroup) ? null : errorsGroup,
this.fieldsStore.getFieldsValue(fieldNames));
}
});
}
setFieldsValue(changedValues, callback) {
const { fieldsMeta } = this.fieldsStore;
// 过滤fieldsStore中没有的字段
const values = this.fieldsStore.flattenRegisteredFields(changedValues);
const newFields = Object.keys(values).reduce((acc, name) => {
const isRegistered = fieldsMeta[name];
if (isRegistered) {
const value = values[name];
acc[name] = {
value,
};
}
return acc;
}, {});
// 设置新值
this.setFields(newFields, callback);
}
setFields(maybeNestedFields, callback) {
const fields = this.fieldsStore.flattenRegisteredFields(maybeNestedFields);
// 更新store中的值
this.fieldsStore.setFields(fields);
//react方法,强制更新组件
this.forceUpdate(callback);
}
Form内部有一套自己的状态管理:fieldsStore,上面记录着所有表单项的信息,通过getFieldDecorator和表单进行双向绑定。