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