import React from 'react' ; import ReactDOM from 'react-dom' ; import { createForm, formShape } from 'rc-form' ; class Form extends React.Component { static propTypes = { form : formShape, componentWillMount ( ) { this . nameDecorator = this . props . form . getFieldDecorator ( 'name' , { initialValue : '' , rules : [{ required : true , message : 'What\'s your name?' , onSubmit = ( e ) => { e. preventDefault (); this . props . form . validateFields ( ( error, values ) => { if (!error) { console . log ( 'ok' , values); } else { console . log ( 'error' , error, values); onChange = ( e ) => { console . log (e. target . value ); render ( ) { const { getFieldError } = this . props . form ; return ( < form onSubmit = {this.onSubmit} > {this.nameDecorator( < input onChange = {this.onChange} < div style = {{ color: ' red ' }}> {(getFieldError('name') || []).join(', ')} </ div > < button > Submit </ button > </ form > const WrappedForm = createForm ()( Form ); ReactDOM . render ( < WrappedForm /> , document . getElementById ( '__react-content' )); 复制代码

上面的例子直接调用了rc-form的createForm方法,第一个参数配置对象未传递,第二个参数是需要被修饰的业务组件 在createForm方法中只是定义了mixin,接着继续调用了最主要的createBaseForm:

function createBaseForm(options={}, mixins={} ) {
    const {
        mapPropsToFields, // 页面初始化或重绘时,将组件接受到的props转变为表单项数据注入this.fields中
        onFieldsChange, // 表单项发生改变时执行函数,可以将表单项的值存入redux.store  
        withRef, // 设定被封装组件的ref属性为"wrappedComponent" 
    } = option;
    //这里的WrappenComponent就是一开始例子中的Form组件
    return funciton decorate(WrappedComponent) {
        const Form = createReactClass({
            mixins,
            getInitialState(){}, // 初始化组件state
            componentWillReceiveProps(nextProps){}, // mark-recProps,初始化部分数据
            onCollect(){}, // 收集表单数据
            onCollectCommon() {},
            getCacheBind() {}, // 组件事件绑定等收集
            getFieldDecorator() {}, // 装饰组件,促进双向绑定的修饰器
            getFieldProps() {} // 设置字段元数据,计算被修饰组件的属性
            render() {
                const { wrappedComponentRef, ...restProps } = this.props;
                const formProps = {
                  [formPropName]: this.getForm(), // createForm mixin
                // 其中mapProps函数就是一个function(obj) {return obj};
                // 这里用了一个小技巧,就是call(this,xxx),直接将该组件上的核心方法,全都放到了子组件的属性上,而且由于该组件是createReactClass创建的,所以子组件(本例中的Form)调用这些从父组件获取的方法时,方法内部的this,指向当前组件。
                const props = mapProps.call(this, {
                  ...formProps,
                  ...restProps,
                // 把form属性挂在到WrappedComponent属性上
                return <WrappedComponent {...props}/>;
        // 复制包裹组件的静态属性到Form上
        return argumentContainer(Form, WrappedComponent);
  • 产生一个新容器组件Form,内置getFieldDecorator、getFieldProps等属性和方法
  • 复制被包裹组件的静态属性到新的组建中,执行生命周期时间,getInitialState初始化默认的field,默认无
  • 最后返回被注入了Form组件的原始组件
  • getFieldDecorator

    getFieldDecorator(name, fieldOption) {
        // 在getFieldProps中初始化store字段,绑定onChange事件以便后续方便做双向数据绑定
        const props = this.getFieldProps(name, fieldOption);
        //props: {value: "", ref: ƒ, onChange: ƒ}
        return (fieldElem) => { // 此处传入被修饰的input元素
          // fieldStore存储字段数据信息以及元数据信息。
          // 数据信息包括value,errors,dirty等
          // 元数据信息包括initValue,defaultValue,校验规则等。
          const fieldMeta = this.fieldsStore.getFieldMeta(name);
          // 获取input上本身绑定的属性,例如该例子中的onChange打印内容函数
          // originalProps属性的主要目的存储被封装表单项的onChange事件,fieldOption下无同类事件时,执行该事件  
          const originalProps = fieldElem.props;
          fieldMeta.originalProps = originalProps;
          fieldMeta.ref = fieldElem.ref;
          // clone input组件,并注入新的属性,onchange,value等
          return React.cloneElement(fieldElem, {
            ...props,
            ...this.fieldsStore.getFieldValuePropValue(fieldMeta),
      getFieldProps(name, usersFieldOption = {}) {
        const fieldOption = {
            name, // 自定义组件名称
            trigger: DEFAULT_TRIGGER, // 绑定默认的onChange事件
            valuePropName: 'value', // 默认值是value属性,checkBox的值为checked
            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;
    复制代码

    将表单项包装为高阶组件

  • 创建表单信息到fieldsStore
  • 绑定默认的onChange事件
  • 保存结果到fieldsStore
  • 返回双向数据绑定的input组件
  • 在上述getFieldProps中onChange绑定了onCollect方法, 当change事件发生时,获取表单项的改变值,有校验规则的表单项添加{dirty:true}属性,调用validateFieldsInternal方法校验该表单项,将结果保存到fieldsStore,触发forceUpdate来重绘表单

    onCollect(name_, action, ...args) {
            const { name, field, fieldMeta } = this.onCollectCommon(name_, action, args);
            const { validate } = fieldMeta;
            const newField = {
              ...field,
              dirty: hasRules(validate),
            this.setFields({
              [name]: newField,
    复制代码

    Form内部有自己的状态管理:fieldsStore记录着所有表单项的信息,通过getFieldDecorator和表单进行双向绑定。

    onChange触发onCollect来改变fieldStore中的值并触发forceUpdate来更新,onCollectCommon方法内部展示了onCollect取值的细节,forceUpdate在更新组件后,触发render方法,接着又回到一开始getFieldDecorator中获取fieldStore内的值,返回被修改后的组件的流程。

  •