摘要:引言看過源碼的都知道,其實是在一組組件的基礎(chǔ)上進(jìn)行了一層封裝,本文主要解讀組件的基礎(chǔ)組件,另外會略過模式下的代碼。解讀源碼首先要從自己最常用的或者感興趣的入手,首先組件最主要的還是在這個裝飾器入手。
引言
看過antd源碼的都知道,antd其實是在一組react-componment組件的基礎(chǔ)上進(jìn)行了一層ui封裝,本文主要解讀antd組件Form的基礎(chǔ)組件react-componment/form,另外會略過development模式下的warning代碼。
Form.create解讀源碼首先要從自己最常用的或者感興趣的入手,首先form組件最主要的還是在Form.create({options})這個裝飾器入手。找到項目下的文件createForm.js,這個文件還是主要主要對createBaseForm.js文件進(jìn)行了一層封裝,提供了一些默認(rèn)配置參數(shù),下看查看createBaseForm.js里的createBaseForm方法,改方法主要是一個裝飾器作用,包裝一個高階React組件,在props里注入一個值為formPropName(默認(rèn)為form)變量,所有功能在這個變量里完成,主要內(nèi)容如下
render() { const { wrappedComponentRef, ...restProps } = this.props; const formProps = { [formPropName]: this.getForm(), // 來在 formPropName默認(rèn)為form,getForm方法來自`createForm.js` }; if (withRef) { formProps.ref = "wrappedComponent"; } else if (wrappedComponentRef) { formProps.ref = wrappedComponentRef; } const props = mapProps.call(this, { ...formProps, ...restProps, }); return; }
在裝飾器初始化的時候,F(xiàn)orm初始化了一個只屬于該組件實例的store,用來存放當(dāng)前Form組件的一些輸入的數(shù)據(jù),主要代碼如下:
const fields = mapPropsToFields && mapPropsToFields(this.props); // mapPropsToFields來自于Form.create的配置參數(shù),用來轉(zhuǎn)化來自mobx或者redux等真正的store來源的value,以初始化該Form實例的fieldsStore this.fieldsStore = createFieldsStore(fields || {}); // createFieldsStore來自于文件`createFieldsStore.js`文件getFieldDecorator
柯里化函數(shù),通過id與參數(shù)聲明的輸入,返回一個函數(shù)以輸入組件為入?yún)⒌暮瘮?shù),通過該函數(shù)聲明的輸入組件與表單Form雙向數(shù)據(jù)綁定。
... getFieldDecorator(name, fieldOption) { const props = this.getFieldProps(name, fieldOption); // 初始化一個field return (fieldElem) => { const fieldMeta = this.fieldsStore.getFieldMeta(name); // 獲取變化(Form的onChange)后的field數(shù)據(jù) const originalProps = fieldElem.props; fieldMeta.originalProps = originalProps; // 輸入組件初始化時保存的Prop fieldMeta.ref = fieldElem.ref; return React.cloneElement(fieldElem, { ...props, ...this.fieldsStore.getFieldValuePropValue(fieldMeta), // 獲取prop屬性 value }); }; } ...getFieldProps
查看函數(shù) getFieldProps,主要用來初始化輸入組件的props,將特定的函數(shù)緩存在內(nèi)部,如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); // 校驗規(guī)則標(biāo)準(zhǔn)化 const validateTriggers = getValidateTriggers(validateRules); validateTriggers.forEach((action) => { if (inputProps[action]) return; inputProps[action] = this.getCacheBind(name, action, this.onCollectValidate); // 如果設(shè)置了輸入校驗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校驗,綁定默認(rèn)的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方法,緩存函數(shù),使用bind方法綁定上下文并緩存部分參數(shù),返回一個新的函數(shù),用做onChange及數(shù)據(jù)校驗。
... 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); // 綁定參數(shù)并返回 } return cache[action]; }, ...onCollectCommon
在getFieldProps方法中看到利用getCacheBind方法當(dāng)無rules的時候綁定了一個onCollect方法,onCollect方法主要調(diào)用onCollectCommon方法,并將得到的結(jié)果保存到store。
onCollectCommon(name, action, args) { const fieldMeta = this.fieldsStore.getFieldMeta(name); if (fieldMeta[action]) { // 如果getFieldDecorator方法中的參數(shù)定義了onChange,則觸發(fā)改onChange fieldMeta[action](...args); } else if (fieldMeta.originalProps && fieldMeta.originalProps[action]) { // 如果輸入組件綁定了onChange,則觸發(fā)該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,則觸發(fā) 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事件,該方法做了除了調(diào)用了onCollectCommon事件以外,還調(diào)用了校驗方法validateFieldsInternal。
validateFieldsInternal該方法主要是從store中獲取rules校驗規(guī)則并標(biāo)準(zhǔn)化后,使用async-validator模塊進(jìn)行校驗,并把結(jié)果保存到store中,本文不做講解。
setFields該方法主要是設(shè)置store中的field,因為store的數(shù)據(jù)是不可觀測的數(shù)據(jù),不會引起頁面的重渲染,該方法也負(fù)責(zé)調(diào)用forceUpdate()強(qiáng)制更新頁面。
setFields(maybeNestedFields, callback) { const fields = this.fieldsStore.flattenRegisteredFields(maybeNestedFields); // 處理field嵌套問題 this.fieldsStore.setFields(fields); if (onFieldsChange) { // 如果設(shè)置有FieldsChange事件監(jiān)聽事件變化,則觸發(fā)事件 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); // 強(qiáng)制更新視圖 },最后
主要方法大概就上面這些,其中流程差不多在每次setFields之前,會在store中存一個field的變化字段fieldMeta,在最后強(qiáng)制更新頁面的時候,將該變量取出來做處理后覆蓋到field,所有數(shù)據(jù)保存在field中,并提供了一些hock方法如setFieldsValue、validateFields等方法設(shè)置和獲取store中的field字段和值。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/94364.html
我們今天來講講關(guān)于ahooks 源碼,我們目標(biāo)主要有以下幾點: 深入了解 React hooks?! ∶靼兹绾纬橄笞远x hooks,且可以構(gòu)建屬于自己的 React hooks 工具庫?! ⌒〗ㄗh:培養(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫是一個對源碼閱讀不錯的選擇?! ×斜眄摮R娫亍 『笈_管理系統(tǒng)中常見典型列表頁包括篩選表單項、Table表格、Pagination分頁這三部分?! ♂槍κ褂?Ant...
摘要:是校驗表單組件數(shù)據(jù)正確性的字段,其值為數(shù)組,里面的數(shù)組元素可以為。所以數(shù)組元素如果為的話,其內(nèi)容就是的。到目前為止,表單適合大部分的表單應(yīng)用場景。 JSON表單 描述 JSON表單是一個基于React的抽象組件,它可以把JSON數(shù)據(jù)格式描述的表單轉(zhuǎn)換成項目中的表單,它可以用簡短的幾行代碼,快速的生成Form表單。JSON表單的優(yōu)點是: 可以快速構(gòu)建出一個表單 表單的數(shù)據(jù)、邏輯、視圖分...
摘要:結(jié)構(gòu)項目結(jié)構(gòu)如下,負(fù)責(zé)外層封裝,負(fù)責(zé)事件綁定與渲染控制。節(jié)點通過決定事件綁定情況,即通過屬性綁定事件情況,事件控制組件的屬性,這里就不詳細(xì)說了。為隱藏狀態(tài)下的添加的,并包裹懶加載組件。 引言 antd的Tooltip組件在react-componment/trigger的基礎(chǔ)上進(jìn)行封裝,而組件Popover和Popconfirm是使用Tooltip組件的進(jìn)行pop,在react-com...
摘要:在裝載組件之前調(diào)用會組件的構(gòu)造函數(shù)。當(dāng)實現(xiàn)子類的構(gòu)造函數(shù)時,應(yīng)該在任何其他語句之前調(diào)用設(shè)置初始狀態(tài)綁定鍵盤回車事件,添加新任務(wù)修改狀態(tài)值,每次修改以后,自動調(diào)用方法,再次渲染組件。可以通過直接安裝到項目中,使用或進(jìn)行引用。 首先我們看一下我們完成后的最終形態(tài):TodoMvc: showImg(https://segmentfault.com/img/remote/14600000085...
摘要:前言這是一個基于實現(xiàn)的一個簡單登入例子,對于剛上手想進(jìn)一步了解,前端頁面如何請求到服務(wù)層路由處理數(shù)據(jù)庫操作返回結(jié)果到頁面這整個過程的同學(xué)比較有用。我們來看下登入請求處理。操作演示演示用戶名不存在,密碼錯誤及成功登入。 前言 這是一個基于node實現(xiàn)的一個簡單登入例子,對于剛上手node想進(jìn)一步了解,前端頁面如何請求到服務(wù)層 -> 路由處理 -> 數(shù)據(jù)庫操作 -> 返回結(jié)果到頁面這整個過...
閱讀 2150·2021-11-16 11:45
閱讀 1276·2021-10-22 09:53
閱讀 4046·2021-09-07 10:26
閱讀 1248·2021-09-06 15:00
閱讀 2101·2019-08-28 18:09
閱讀 2843·2019-08-26 14:06
閱讀 4033·2019-08-26 13:48
閱讀 1332·2019-08-26 12:11