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