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

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

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

溫馨提示

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

評論

0/150

提交評論