摘要:數(shù)據(jù)信息包括等元數(shù)據(jù)信息包括,校驗(yàn)規(guī)則等。第一次元數(shù)據(jù)一般得不到,內(nèi)部會(huì)返回個(gè)空對(duì)象這里的簡(jiǎn)化后結(jié)果為,第一次為空。
前言
第一次探索這個(gè)框架,對(duì)于里面很多邏輯是不懂的,所以只能一點(diǎn)一點(diǎn)去揣摩,其中做了什么。
而學(xué)習(xí)過程中,總是禁不住好奇這里的邏輯是干什么的,那里的邏輯是什么的,在不理解這段邏輯是做什么的情況下,死磕很容易事倍功半。所以本次先從一個(gè)比較簡(jiǎn)單的場(chǎng)景入手,看看它的源碼中做了什么手腳,至于有些邏輯沒有涉及到的,先不去管它就好了。
首先上圖,看看這次案例的效果。
其實(shí)是上一篇案例的精簡(jiǎn)版,去掉了非空驗(yàn)證。但是分析的更細(xì)致些。
業(yè)務(wù)代碼import React from "react"; import { createForm, formShape } from "rc-form"; class Form extends React.Component { static propTypes = { form: formShape, }; componentWillMount() { this.nameDecorator = this.props.form.getFieldDecorator("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 (); } } const WrappedForm = createForm()(Form); export default WrappedForm; 源碼分析
PS: 源碼分析以代碼+備注的形式展示
WrappedForm 概述這個(gè)頁(yè)面直接渲染了WrappedForm,所以我們不妨直接從WrappedForm看起。
其中WrappedForm是由rc-form提供的createForm創(chuàng)建的,第一個(gè)配置對(duì)象未傳遞,第二個(gè)參數(shù)是要修飾的組件。這里傳遞給了我們的業(yè)務(wù)組件
import createBaseForm from "./createBaseForm"; // 一系列給其他組件用的自定義混入 export const mixin = { getForm() { // 這里需要注意的是this是動(dòng)態(tài)的,所以這里的this.xxx會(huì)根據(jù)環(huán)境改變而改變 return { getFieldsValue: this.fieldsStore.getFieldsValue, getFieldValue: this.fieldsStore.getFieldValue, getFieldInstance: this.getFieldInstance, setFieldsValue: this.setFieldsValue, setFields: this.setFields, setFieldsInitialValue: this.fieldsStore.setFieldsInitialValue, getFieldDecorator: this.getFieldDecorator, getFieldProps: this.getFieldProps, getFieldsError: this.fieldsStore.getFieldsError, getFieldError: this.fieldsStore.getFieldError, isFieldValidating: this.fieldsStore.isFieldValidating, isFieldsValidating: this.fieldsStore.isFieldsValidating, isFieldsTouched: this.fieldsStore.isFieldsTouched, isFieldTouched: this.fieldsStore.isFieldTouched, isSubmitting: this.isSubmitting, submit: this.submit, validateFields: this.validateFields, resetFields: this.resetFields, }; }, }; function createForm(options) { // 這里調(diào)用了createBaseForm并將混入傳入到該函數(shù) return createBaseForm(options, [mixin]); } export default createForm;
這里我們看到,其實(shí)createForm本身沒做什么事情,只是在該文件內(nèi)定義了混入的格式。
接下來我們的重點(diǎn)是createBaseForm中做了什么。這里只列出跟我們案例相關(guān)的內(nèi)容
//整體結(jié)構(gòu) function createBaseForm(options={}, mixins={} ) { const { mapPropsToFields, onFieldsChange, // ****其他的optinos里面的值,下文可能會(huì)用到 } = option; //此處的WrappedComponent就是我們示例中,被包裹的Form組件 return funciton decorate(WrappedComponent) { const Form = createReactClass({ // 該混入包含一個(gè)getForm方法用來得到一些通用方法 mixins, getInitialState() {/*mark-init,初始化組件state*/} componentWillReceiveProps(nextProps) {/*mark-recProps,初始化部分?jǐn)?shù)據(jù)*/} onCollect(){/*mark-collect收集表單數(shù)據(jù)*/} onCollectCommon() {} getCacheBind() {/*mark-bind組件事件綁定等收集*/} getFieldDecorator() {/*mark-deco裝飾組件,促進(jìn)雙向綁定的修飾器*/} getFieldProps() {/*mark-props設(shè)置字段元數(shù)據(jù),計(jì)算被修飾組件的屬性*/} // 一些其他函數(shù) render() { const { wrappedComponentRef, ...restProps } = this.props; const formProps = { [formPropName]: this.getForm(), }; // ** 精簡(jiǎn)本次分析無關(guān)的代碼 // 其中mapProps函數(shù)就是一個(gè)function(obj) {return obj}; // 這里用了一個(gè)小技巧,就是call(this,xxx),直接將該組件上的核心方法,全都放到了子組件的屬性上,而且由于該組件是createReactClass創(chuàng)建的,所以子組件(本例中的Form)調(diào)用這些從父組件獲取的方法時(shí),方法內(nèi)部的this,指向當(dāng)前組件。 const props = mapProps.call(this, { ...formProps, ...restProps, }); return; }, }, }) //簡(jiǎn)化靜態(tài)方法轉(zhuǎn)移部分 return Form; } }
當(dāng)createBaseForm函數(shù)在渲染函數(shù)中返回了我們的Form組件后,就可以看到Form組件中做的事情。
Form.jsclass Form extends React.Component { static propTypes = { form: formShape, }; componentWillMount() { // 上個(gè)文件,createBaseForm的裝飾器函數(shù)decorate,生成的組件中渲染了該組件, // 并將getFieldDecorator方法通過屬性傳遞給了它。 this.nameDecorator = this.props.form.getFieldDecorator("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 (); } }
重點(diǎn)了。關(guān)鍵是看看getFieldDecorator中做了什么。
getFieldDecorator(name, fieldOption) { // 獲取需要傳遞給被修飾元素的屬性。包括onChange,value等 // 同時(shí)在該props中設(shè)定用于收集元素值得監(jiān)聽事件(onChange),以便后續(xù)做雙向數(shù)據(jù)。 const props = this.getFieldProps(name, fieldOption); // 通過該函數(shù)傳入(input/被修飾)元素。 return (fieldElem) => { // 此處fieldStore存儲(chǔ)字段數(shù)據(jù)信息以及元數(shù)據(jù)信息。 // 數(shù)據(jù)信息包括value,errors,dirty等 // 元數(shù)據(jù)信息包括initValue,defaultValue,校驗(yàn)規(guī)則等。 const fieldMeta = this.fieldsStore.getFieldMeta(name); // 獲取input上本身綁定的屬性,例如該例子中的onChange打印內(nèi)容函數(shù) const originalProps = fieldElem.props; fieldMeta.originalProps = originalProps; fieldMeta.ref = fieldElem.ref; return React.cloneElement(fieldElem, { ...props, ...this.fieldsStore.getFieldValuePropValue(fieldMeta), }); }; },
其中getFieldProps值得我們關(guān)注
// 簡(jiǎn)化后的內(nèi)容如下 getFieldProps(name, usersFieldOption = {}) { // name為我們?yōu)樵撐谋究蚱鸬膎ame // 這里的數(shù)據(jù)fieldOption用來初始后面的FieldMeta。 const fieldOption = { name, trigger: "onChange", valuePropName: "value", // checkBox取值時(shí)通過checked屬性。 ...usersFieldOption, }; const { trigger, validateTrigger = trigger, } = fieldOption; // 第一次get元數(shù)據(jù)一般得不到,內(nèi)部會(huì)返回個(gè)空對(duì)象 const fieldMeta = this.fieldsStore.getFieldMeta(name); if ("initialValue" in fieldOption) { fieldMeta.initialValue = fieldOption.initialValue; } // 這里的inputProps簡(jiǎn)化后結(jié)果為{value: xxx},第一次為空。 const inputProps = { ...this.fieldsStore.getFieldValuePropValue(fieldOption), }; // make sure that the value will be collect // 這里用來在getFieldDecorator第二個(gè)參數(shù)為空時(shí),確保給input綁定一個(gè)基本的onChange事件來收集input的修改值,最終放入fieldsStore中 if (trigger && validateTriggers.indexOf(trigger) === -1) { inputProps[trigger] = this.getCacheBind(name, trigger, this.onCollect); } // 這里就是我們fieldsStore中設(shè)置的元數(shù)據(jù) const meta = { ...fieldMeta, ...fieldOption, }; this.fieldsStore.setFieldMeta(name, meta); // 這里返回的{value: "xxx", onChange: fn}; return inputProps; },
上述代碼中onChange綁定了一個(gè)onCollect,其中g(shù)etCacheBind函數(shù)主要是修正函數(shù)使用時(shí)候this指針。此處忽略直接分析onCollect
onCollect(name_, action, ...args) { // 通過onCollectCommon在input的onChange中觸發(fā),收集到該元素相關(guān)東西 const { name, field, fieldMeta } = this.onCollectCommon(name_, action, args); const { validate } = fieldMeta; const newField = { ...field, dirty: hasRules(validate),//根據(jù)規(guī)則驗(yàn)證,此處可忽略 }; // 更新fieldStore中的值,主要觸發(fā)了一個(gè)forceUpdate方法,重新渲染該組件 this.setFields({ [name]: newField, }); },
最后關(guān)鍵的一步就是看看onCollectCommon做了什么
onCollectCommon(name, action, args) { const fieldMeta = this.fieldsStore.getFieldMeta(name); if (fieldMeta[action]) { fieldMeta[action](...args); } else if (fieldMeta.originalProps && fieldMeta.originalProps[action]) { // 此處調(diào)用input原來的onChange事件,即打印輸入值,這個(gè)originalProps是在getFieldDecorator函數(shù)中存下的,這里只不過拿來用了。 fieldMeta.originalProps[action](...args); } // 此處的getValueFromEvent其實(shí)就是取e.target.value. const value = fieldMeta.getValueFromEvent ? fieldMeta.getValueFromEvent(...args) : getValueFromEvent(...args); const field = this.fieldsStore.getField(name); return ({ name, field: { ...field, value, touched: true }, fieldMeta }); },
至此整個(gè)數(shù)據(jù)流程基本跑通,onChange觸發(fā)onCollect去改變fieldStore中的值并forceUpdate更新界面,onCollectCommon則展示了onCollect取值的細(xì)節(jié)。forceUpdate更新組件后,觸發(fā)Form的render方法,又開始了之前getFieldDecorator 中讀取fieldStore中值,返回被修改后的組件的流程。
題外話跑通了最簡(jiǎn)單的場(chǎng)景,就可以向下一步更復(fù)雜的場(chǎng)景探索了。
結(jié)語(yǔ)至此一個(gè)最簡(jiǎn)單的流程已經(jīng)分析完畢。接下來,需要考慮的就是表單驗(yàn)證,數(shù)據(jù)反顯(從后端拿到數(shù)據(jù)渲染編輯頁(yè)面)等等,一步一個(gè)腳印,慢慢來吧。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/95979.html
摘要:它包含了一組完善而且容易理解的標(biāo)準(zhǔn)庫(kù),能夠輕松完成很多常見的任務(wù)。代碼這是自年恢復(fù)高考以來到年的高考報(bào)考及錄取數(shù)據(jù)。為了直觀展示,對(duì)錄取率做了尺度上的變換。 Python(發(fā)音:英[?pa?θ?n],美[?pa?θɑ:n]),是一種面向?qū)ο蟆⒅弊g式電腦編程語(yǔ)言,也是一種功能強(qiáng)大的通用型語(yǔ)言,已經(jīng)具有近二十年的發(fā)展歷史,成熟且穩(wěn)定。它包含了一組完善而且容易理解的標(biāo)準(zhǔn)庫(kù),能夠輕松完成很多常...
摘要:算法之最常用的排序參加百度前端的課程真的是好多知識(shí)點(diǎn)不知道。快速排序也是在實(shí)際中最常用的一種排序算法,速度快,效率高。插入排序的思路很簡(jiǎn)單,很清晰,是一種最常見最簡(jiǎn)單的排序方法。 js算法之最常用的排序 參加百度前端的課程真的是好多知識(shí)點(diǎn)不知道。邊學(xué)邊做題,在問題中學(xué)習(xí),知識(shí)點(diǎn)從點(diǎn)到面,但是要善于總結(jié)記錄才行。加油吧,騷年! 可視化排序網(wǎng)站 時(shí)間復(fù)雜度是衡量一個(gè)算法效率的基本方法我們把...
摘要:支持表單雙向綁定,開發(fā)過程中無需通過回調(diào)函數(shù)去獲取組件的值,通過可以自動(dòng)完成數(shù)據(jù)綁定的功能。如果我們通過獲取了數(shù)據(jù)之后,表單數(shù)據(jù)不會(huì)發(fā)生變化。注意使用這個(gè)函數(shù)必須用封裝需要綁定的字段。 antd支持表單雙向綁定,開發(fā)過程中無需通過onChange()回調(diào)函數(shù)去獲取組件的值,通過 getFieldDecorator() 可以自動(dòng)完成數(shù)據(jù)綁定的功能。 { getFieldDecor...
摘要:擅長(zhǎng)網(wǎng)站建設(shè)微信公眾號(hào)開發(fā)微信小程序開發(fā)小游戲制作企業(yè)微信制作建設(shè),專注于前端框架服務(wù)端渲染技術(shù)交互設(shè)計(jì)圖像繪制數(shù)據(jù)分析等研究。 Ant Design of React @3.10.9 拉取項(xiàng)目 luwei.web.study-ant-design-pro, 切換至 query 分支,可看到 Form 表單實(shí)現(xiàn)效果 實(shí)現(xiàn)一個(gè)查詢表單 showImg(https://segmentfau...
摘要:記錄下與有關(guān)的常用方法,如求最大值最小值等,或者是保留幾位數(shù)啥的數(shù)據(jù)求最大值最小值求最小值使用來重新綁定使用展開運(yùn)算符求最大值使用來重新綁定使用展開運(yùn)算符取整四舍五入取整取與參數(shù)最接近的整數(shù)向上取整取大于或等于函數(shù)參數(shù),并且與之最接近的 記錄下與Math有關(guān)的常用方法,如:求最大值、最小值等,或者是保留幾位數(shù)啥的 1.數(shù)據(jù) let floatA = 2.325232; let floa...
閱讀 865·2021-10-09 09:44
閱讀 756·2019-08-30 13:55
閱讀 3220·2019-08-29 15:07
閱讀 3278·2019-08-29 13:09
閱讀 2466·2019-08-29 11:10
閱讀 1358·2019-08-26 14:05
閱讀 3682·2019-08-26 13:57
閱讀 2258·2019-08-23 16:42