數(shù)據(jù)如何在react組件之間流動量資源_第1頁
數(shù)據(jù)如何在react組件之間流動量資源_第2頁
數(shù)據(jù)如何在react組件之間流動量資源_第3頁
數(shù)據(jù)如何在react組件之間流動量資源_第4頁
數(shù)據(jù)如何在react組件之間流動量資源_第5頁
已閱讀5頁,還剩14頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

本文由簡悅SimpRead轉(zhuǎn)碼,原文地址通過前面本文由簡悅SimpRead轉(zhuǎn)碼,原文地址通過前面3個課時的學(xué)習(xí),相信你已經(jīng)對React生命周期相關(guān)的“Why”“What”和“Hw”有了系統(tǒng)的理解和掌握。當(dāng)我們談?wù)撋芷跁r,其實談?wù)摰氖墙M件的“內(nèi)心世界”要擁有豐富的內(nèi)心世界,還應(yīng)該建立健全的“人際關(guān)系”溝通和表達(dá)。從本課時開始,我們將一起探索蘊含在React組件中的“溝通與表達(dá)”的藝術(shù)。我們知道,React的核心這個表達(dá)式有很多的版本,一些版本會把入?yún)⒗锏膁ata替換成state,但它們本質(zhì)上都指向同一個含義,那就是React的視圖會隨著數(shù)據(jù)的變化而變化。數(shù)據(jù)這個角色在React中的地位可見一斑。在React中,如果說兩個組件之間希望能夠產(chǎn)生“耦合”(即A組件希望能夠通過某種方式影響到B組件),“組件間通信”?!敖M件間通信”的背后是一套環(huán)環(huán)相扣的React數(shù)據(jù)流解決方案。雖然這套解決方案在業(yè)內(nèi)已經(jīng)有了比較在前面三個課時中,我們的學(xué)習(xí)思路是往縱深處去尋覓:鋪陳大量的前置知識,然后一步一步地去詢問生命周期背后的“Why”,最終揪出Fiber架構(gòu)這個大boss(不過學(xué)到這里,這個“縱深”一半,專欄第二模塊還有一大波Fiber原理等待我們繼續(xù)尋覓)。在接下來的第04和05課時中,我們要做的事情則更傾向于橫向的“聚合”你理解當(dāng)下實踐中React這些知識本身并不難,但攤子卻可以鋪得非常大,相關(guān)的問題在面試中也始終具備較高的區(qū)分度。要想扎扎實實掌握,必須耐下心、沉住氣,在學(xué)習(xí)過程中主動地去串聯(lián)自己的知識鏈路。既然pops不過,這個“修改”也是有原則的——你必須確保所有操作都在既然pops不過,這個“修改”也是有原則的——你必須確保所有操作都在“單向數(shù)據(jù)流”這個前提下。所謂單向數(shù)據(jù)流,指的就是當(dāng)前組件的state以props的形式流動時,只能流向組件樹中比自己層級更低的組件。比如在父-子組件這種嵌套關(guān)系中,只能由父組件傳props給子組件,而不能反過來。聽上去雖然限制重重,但用起來卻是相當(dāng)?shù)撵`活?;趐rops傳參這種形式,我們可以輕松實現(xiàn)父-子通信、子-父通信和兄弟組件通信。這是最常見、也是最好解決的一個通信場景。React的數(shù)據(jù)流是單向的,父組件可以直接將傳入子組件,實現(xiàn)父-return<div<p>{`classFatherextendsReact.Componentstate=text:"初始化的父組件的文本changeText=()=>text:"改變后的父組件文本state=text:"初始化的父組件的文本changeText=()=>text:"改變后的父組件文本render()return<div<button{/*引入子組件,并通過props下發(fā)具體的狀態(tài)值實現(xiàn)父-<ChildfatherText={this.state.text}通過子組件順利讀取到父組件的ps.text,從這一點可以看出,父-子之間的通信是沒有問題的。此時假如我們點擊父組件中的按鈕,父組件的this.state.text會發(fā)生變化,同時子組件讀取到的通過子組件順利讀取到父組件的ps.text,從這一點可以看出,父-子之間的通信是沒有問題的。此時假如我們點擊父組件中的按鈕,父組件的this.state.text會發(fā)生變化,同時子組件讀取到的props.text也會跟著發(fā)生變化(如下圖所示),也就是說,父子組件的數(shù)據(jù)始終保持一致。由此我們便充分驗證了父-子組件基于props考慮到pops是單向的,子組件并不能直接將自己的數(shù)據(jù)塞給父組件,但pops的形式也可以是多樣的。假如父組件傳遞給子組件的是一個綁定了自身上下文的函數(shù)將想要交給父組件的數(shù)據(jù)以函數(shù)入?yún)⒌男问浇o出去這里我們只需對父-子通信中的示例稍做修改,就可以完成子-首先是對子組件的修改。在Child中,我們需要增加對狀態(tài)的維護,以及對Father組件傳入的函數(shù)形classChildextendsReact.Componentstate=text:'子組件的文本changeText=()=>render()return<div{/*Child<button在父組件中,我們只需要在render()return<div{/*Child<button在父組件中,我們只需要在changeTextchangeText放在propsclassFatherextendsReact.Componentstate=text:"初始化的父組件的文本changeText=(newText)=>text:render()return<div<p>{`{/*propstext:render()return<div<p>{`{/*props實現(xiàn)子-注意,在這個case當(dāng)點擊子組件中的按鈕時,會調(diào)用已經(jīng)綁定了父組件上下文的this.pops.changeFather當(dāng)點擊子組件中的按鈕時,會調(diào)用已經(jīng)綁定了父組件上下文的this.pops.changeFatherxt時將子組件的this.state.txt以函數(shù)入?yún)⒌男问絺魅?,由此便能夠間接地用子組件的state去更新父組件的state。這個先決條件使得我們可以繼續(xù)利用父子組件這一層關(guān)系,將“兄弟1→兄弟2”之間的通信,轉(zhuǎn)化為“兄弟1→父組件”(子-父通信)、“父組件→兄弟2”(父-子)通信兩個步驟,如下圖所示,這樣一來就能夠巧妙地把“兄弟”之間的新問題化解為“父子”之間的舊問題。接下來我們?nèi)匀粡木幋a的角度進行驗證。首先新增一個NewChild組件作為與接下來我們?nèi)匀粡木幋a的角度進行驗證。首先新增一個NewChild組件作為與Child組件同層級的兄弟組件。NewChild將作為數(shù)據(jù)的發(fā)送方,將數(shù)據(jù)發(fā)送給Child。在NewChild中,我們需要處理NewChildFather之間的關(guān)系。NewChild組件編碼如下:classNewChildextendsReact.Componentstate=textnewChild的文本changeText=()=>render()return<div{/*注意這里把修改父組件文本(Child組件的文本)NewChild<button<div{/*注意這里把修改父組件文本(Child組件的文本)NewChild<buttononClick={this.changeText}>點擊更新Child組件的文本接下來看看Father組件。在Father組件中,我們通過text屬性連接Father和Child,通過changeTextFatherNewChildtextChildtext屬到classFatherextendsReact.Componentstate=text:"初始化的父組件的文本changeText=(newText)=>text:render()由于整體結(jié)構(gòu)稍微復(fù)雜了一些,這里我把Father、Child和NewChild由于整體結(jié)構(gòu)稍微復(fù)雜了一些,這里我把Father、Child和NewChild紅色所圈范圍為Father組件,它包括了Child和灰色圈住的按鈕是NewChild組件的渲染結(jié)果,它可以觸發(fā)數(shù)據(jù)的改變;藍(lán)色圈住的文本是Child組件的渲染結(jié)果,它負(fù)責(zé)感知和渲染數(shù)據(jù)?,F(xiàn)在我點擊位于NewChild組件中的“點擊更新Child組件的文本”按鈕,就可以看到Child會跟著發(fā)生return<div{/*引入Child組件,并通過props中下發(fā)具體的狀態(tài)值實現(xiàn)父-<ChildfatherText={this.state.text}{/*NewChildprops-<NewChildchangeFatherText={this.changeText}至此,我們給出了p至此,我們給出了pops傳參這種形式比較適合處理的三種場景。盡管這并不意味著其他場景不能用pops處理,但如果你試圖用簡單的pops你舉一個比較極端的例子:如上圖所示,可以看到這是一個典型的多層嵌套組件結(jié)構(gòu)。A組件倘若想要和層層相隔的E組件實現(xiàn)通信,就必須把props經(jīng)過B、C、D一層一層地傳遞下去。在這個過程中,反反復(fù)復(fù)的props傳遞不僅會帶來龐大的工作量和代碼量,還會污染中間無辜的B、C、D組件的屬性結(jié)構(gòu)。成本都會變得非常高昂。因此,層層傳遞pops要不得。那有沒有更加靈活的解決方案,能夠幫我們處理“任意組件”之間的通信需求呢?答案是不僅有,而且姿勢還很多。我先從最樸素的“發(fā)布-訂閱”模式講起。“發(fā)布-訂閱”模式可謂是解決通信類問題的“萬金油”,在前端世界的應(yīng)用非常廣泛,比如:前兩年爆火的socket.io模塊,它就是一個典型的跨端發(fā)布訂閱模式的實現(xiàn);在Node.js中,許多原生模塊也是以EventEmitter不過大家最為熟知的,應(yīng)該還是Vue.js中作為常規(guī)操作被推而廣之的“全局事件總線”EventBus。不過大家最為熟知的,應(yīng)該還是Vue.js中作為常規(guī)操作被推而廣之的“全局事件總線”EventBus。理解事件的發(fā)布發(fā)布-訂閱機制早期最廣泛的應(yīng)用,應(yīng)該是在瀏覽器的DOM事件中。相信有過原生JavaScript開發(fā)target.addEventListener(type,listener,通過調(diào)用addEventListener方法,我們可以創(chuàng)建一個事件監(jiān)聽器,這個動作就是“訂閱”。比如我可以監(jiān)聽click(點擊)事件:el.addEventListener("click",func,這樣一來,當(dāng)click事件被觸發(fā)時,事件會被“發(fā)布”出去,進而觸發(fā)監(jiān)聽這個事件的func函數(shù)。這就是一個最簡單的發(fā)布-訂閱案例。使用發(fā)布-訂閱模式的優(yōu)點在于,監(jiān)聽事件的位置和觸發(fā)事件的位置是不受限的里,只要它們在同一個上下文里,就能夠彼此感知。這個特性,太適合用來應(yīng)對“任意組件通信”這種場通過前面的講解,不難看出發(fā)布-訂閱模式中有兩個關(guān)鍵的動作:事件的監(jiān)聽(訂閱)(發(fā)布),這兩個動作自然而然地對應(yīng)著兩個基本的APIemit():負(fù)責(zé)觸發(fā)事件,可以通過傳參使其在觸發(fā)的時候攜帶數(shù)據(jù)。最后,只進不出總是不太合理的,我們還要考慮一個o?()方法,必要的時候用它來刪除用不到的監(jiān)聽o?()發(fā)布“發(fā)布-訂閱”模式不僅在應(yīng)用層面十分受歡迎,它更是面試官的心頭好。在涉及設(shè)計模式的面試中,如果只允許出一道題,那么我相信大多數(shù)的面試官都會和我一樣,會毫不猶豫地選擇考察“發(fā)布-訂閱模式的實現(xiàn)”。接下來我就手把手帶你來做這道題,寫出一個同時擁有on、emit和o?的EventEmitter在寫代碼之前,先要捋清楚思路。這里我把“實現(xiàn)EventEmitter”這個大問題,拆解為3個具體的小問提到“對應(yīng)關(guān)系”,應(yīng)該聯(lián)想到的是“映射”。在JavaScript中,處理“映射”我們大部分情況下都是用對象constructor()this.eventMap=所謂“訂閱”,也就是注冊事件監(jiān)聽函數(shù)的過程。這是一個“寫”操作,具體來說就是把事件和對應(yīng)的監(jiān)聽函數(shù)寫入到eventMap里面去:on(type,handler)constructor()this.eventMap=所謂“訂閱”,也就是注冊事件監(jiān)聽函數(shù)的過程。這是一個“寫”操作,具體來說就是把事件和對應(yīng)的監(jiān)聽函數(shù)寫入到eventMap里面去:on(type,handler)thrownewError("if(!this.eventMap[type])訂閱操作是一個“寫”操作,相應(yīng)的,發(fā)布操作就是一個“讀”操作。發(fā)布的本質(zhì)是觸發(fā)安裝在某個事件上的監(jiān)聽函數(shù),我們需要做的就是找到這個事件對應(yīng)的監(jiān)聽函數(shù)隊列,將隊列中的handler隊:emit(type,params)if(this.eventMap[type])this.eventMap[type].forEach((handler,index)=>到這里,最最關(guān)鍵的on方法和emit方法就實現(xiàn)完畢了。最后我們補充一個o?off(type,handler)if(this.eventMap[type])到這里,最最關(guān)鍵的on方法和emit方法就實現(xiàn)完畢了。最后我們補充一個o?off(type,handler)if(this.eventMap[type])接著把這些代碼片段拼接進一個class里面,一個核心功能完備的EventEmitterclassmyEventEmitterconstructor()this.eventMap=on(type,handler)if(!(handlerinstanceofFunction))thrownewError("if(!this.eventMap[type])emit(type,params)emit(type,params)off(type,handler)>>>0,myEventEmittermyEventmyEventEmitter的實例,然后針對名為“test”的事件進行監(jiān)聽和觸發(fā):constmyEvent=newconsttestHandler=function(params)console.log(`testconsttestHandler=function(params)console.log(`test事件被觸發(fā)了,testHandler接收到的入?yún)⑹莔yEvent.on("test",myEvent.emit("test",由此可以看出,EventEmitter的實例已經(jīng)具備發(fā)布-現(xiàn)在你可以試想一下,對于任意的兩個組件A和B,假如我希望實現(xiàn)雙方之間的通信,借助EventEmitter來做就很簡單了,以數(shù)據(jù)從A流向B為例。Bhandler(handlerthisB身上),handler中進constglobalEvent=classBextendsReact.Componentstate=handler=(params)=>bindHandler=()=>globalEvent.on("someEvent",render()bindHandler=()=>globalEvent.on("someEvent",render()return<buttononClick={this.bindHandler}>點我監(jiān)聽A的動作<div>A傳入的內(nèi)容是接下來在A組件中,只需要直接觸發(fā)對應(yīng)的事件,然后將希望攜帶給B的數(shù)據(jù)作為入?yún)鬟f給emit方classAextendsReact.Componentstate=infoToB:"哈哈哈哈我來自repo

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論