informed源碼解析

informed的源碼有三個(gè)重點(diǎn): FormController和FieldController以及withFieldStuff函數(shù)。他們的關(guān)系如下所示:


image.png

FormController

FormController是核心。它有三個(gè)屬性: values,field,以及errorsvalueserrors的數(shù)據(jù)類(lèi)型ObjectMap(為什么要用這個(gè)數(shù)據(jù)格式我沒(méi)有搞懂),fieldmap類(lèi)型,一個(gè)fieldName綁定一個(gè)對(duì)應(yīng)的fieldController。FormController 繼承EventEmitter,繼承這個(gè)庫(kù)在以下功能中都有用到。這里主要介紹setValue/getValue/register方法

ObjectMap

ObjectMap的數(shù)據(jù)類(lèi)型有三個(gè)屬性:objects, map,path。path的格式是這樣的

{
      'a.b.c':[a,b,c],
      'a.b[1]':[a, b, 1]
}

objects就是fieldNamevalue的一一對(duì)應(yīng),比如:

{
       a:{
            b:{
                c: 'hello'
            }
      }
}

map的數(shù)據(jù)格式如下所示

image.png

這個(gè)class有還有getset方法。基本上就是遍歷設(shè)置和獲取對(duì)應(yīng)field的值。
這里我有一個(gè)疑問(wèn)了,我刷了整個(gè)informed的方法,用到map的寥寥無(wú)幾,這個(gè)屬性有存在的必要嗎?

values

values中存儲(chǔ)的是每一個(gè)包含在form表單中組件的值。它是一個(gè)特殊的數(shù)據(jù)格式(ObjectMap)
和這個(gè)屬性相關(guān)的有兩個(gè)函數(shù): setValuegetValue,顧名思義。

  • setValue
    setValue的代碼如下:
this.values.set(
      field,
      fieldController.config.mask ? fieldController.config.mask(value) : value
    ); 
...
this.emit('change', this.state);
this.emit('values', this.state.values);
this.emit('field', field);

重點(diǎn)是這三個(gè)事件changevaluesfield。那么接收change事件調(diào)用的函數(shù)在Form組件中的constructor

 this.controller.on('change', () => this.forceUpdate());

調(diào)用的是react的forceUpdate方法。會(huì)讓form下的所有子組件重新渲染。
接收field事件的函數(shù),是在withFieldStuff函數(shù)中。

const buildFieldState = (formApi, field) => {
  return {
    value: formApi.getValue(field),
    touched: formApi.getTouched(field), //touch并不知道干嘛用的
    error: formApi.getError(field),
    asyncError: formApi.getAsyncError(field)
  };
};
....
const updateMe = name => {
     if (name === formApi.getFullField(field)) {
              //重新獲取field對(duì)應(yīng)新的value的值
              this.setState(buildFieldState(formApi, field));
    }
 };

controller.on('field', updateMe);

以上代碼,當(dāng)接收到field事件時(shí),每一個(gè)包裹Field的input,都會(huì)從FormController中重新獲取當(dāng)前field的最新的值。

FieldController

FieldController的代碼如下所示:


class FieldController {
  constructor(field, api, config) {
    this.field = field;
    this.config = config;
    this.api = api;
  }
  validate(values) {
    if (this.config.validate) {
      return this.config.validate(this.api.getValue(), values);
    }
  }
  asyncValidate(values) {
    if (this.config.asyncValidate) {
      return this.config.asyncValidate(this.api.getValue(), values);
    }
  }
  updateConfig(config) {
    this.config = config;
  }
}

FieldController主要對(duì)傳入的this.config.validate函數(shù)進(jìn)行一層封裝。創(chuàng)建FieldController函數(shù)的代碼如下所示:

this.fieldController = new FieldController(
              formApi.getFullField(field),
              this.fieldApi,
              {
                validateOnBlur,
                validateOnChange,
                validate,
                onValueChange,
                asyncValidate,
                asyncValidateOnBlur,
                initialValue,
                validateOnMount,
                notify,
                mask
              }
            );

Field初始化時(shí)(constructor ),會(huì)為每一個(gè)field創(chuàng)建一個(gè)controller。
那什么時(shí)候使用這個(gè)constroller的valiate函數(shù)呢?在formControllersetValuesetTouched函數(shù)都有,前提要配置一些參數(shù)

setValue函數(shù)中的,如果配置了validateOnChange

...
 if (fieldController.config.validateOnChange) {
      this.errors.set(field, fieldController.validate(this.state.values));
      // We changed so notify all other fields
      this.notify(fieldController.config.notify);
    }
...

setTouched函數(shù),如果配置了validateOnBlur

if (fieldController.config.validateOnBlur) {
      this.errors.set(field, fieldController.validate(this.state.values));
      // We changed so notify all other fields
      this.notify(fieldController.config.notify);
    }

withFieldStuff函數(shù)

withFieldStuff函數(shù)是連接FieldControllerFormController之間的橋梁。同時(shí)也從formApi中獲取本field相關(guān)的函數(shù)和值。主要的函數(shù)是register函數(shù)。該函數(shù)會(huì)在Field組件componentDidMount中調(diào)用

class Field extends PureComponent  {
 constructor(props) {
    super(props);
    this.me = React.createRef();
  }

 componentDidMount() {
  
    this.props.register();
  }

}

接下來(lái)看register函數(shù)的流程。

image.png

整個(gè)informed源碼的重點(diǎn)部分就說(shuō)完了

問(wèn)題:
1.如果我在組件A中需要用到組件B的值?(這個(gè)在表單中非常常見(jiàn))
2.作者創(chuàng)建一個(gè)objectMap數(shù)據(jù)類(lèi)型意義何在?

以后的話:
我看的這個(gè)版本的informed源碼是比較老。新的版本又出了,使用了hook的技術(shù)。所以這個(gè)系列未完待續(xù)。

`

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 3,129評(píng)論 0 3
  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 14,235評(píng)論 0 38
  • 你說(shuō),十六歲才剛開(kāi)始 遇見(jiàn)我,是第一塊石頭 我說(shuō),不管不顧,只走到最后,再看結(jié)果怎么樣 想你??!想你…… 只要你不...
    齊家能閱讀 256評(píng)論 0 2
  • 今日體驗(yàn):今天不是很忙 做好本職工作 快過(guò)年了 保證好安全以及自身安全!
    酷酷的峰666閱讀 176評(píng)論 0 0
  • 有這樣一個(gè)男孩,他樂(lè)觀但卻會(huì)在深夜憂傷,他熱情卻又似乎什么都不在乎,他很簡(jiǎn)單但卻遇見(jiàn)了他喜歡的她。 他喜歡她在雨里...
    寂跡閱讀 215評(píng)論 0 1

友情鏈接更多精彩內(nèi)容