React 精要面試題講解(二) 組件間通信詳解


單向數據流與組件間通信

 上文我們已經講述過,react 單向數據流的原理和簡單模擬實現。結合上文中的代碼,我們來進行這節面試題的講解: react中的組件間通信。

 那么,首先我們把看上文中的原生js代碼:
        function child(props){
           this.props = props;
        }
       function parent(props){ 
           this.props = props              
           this.state = '這是父函數的一個狀態'
           this.childNodes  = new child(this.state); 
        }
       console.log(new parent('這是一個屬性'));
 ok,經過運行,我們發現打印結果的結構 和 react父子組件的關系結構是極為類似的,子函數通過props形參接受到父函數的state。
 這個好理解吧?那么在說react組件通信之前,我們基於原生繼續模擬父子組件間的通信。
 如上文代碼所示,我們已經實現了父函數通過props這個形參向子函數傳遞數據——是的,相對而言,在react中,父組件通過props(規定了只能通過props傳遞及獲取)向子組件進行數據傳遞。換句話講,props這個實例屬性,表面唯一的作用就是參數傳值…

那么,我們接來下要思考一個問題,如何在上述代碼中實現 子函數向父函數傳遞數據?

 如果我們把函數玩的夠熟練,那么很容易會思考到以下實現方式:
        function child(props){
           this.data = '我是子函數中的data'
           props.getChildData(this.data);
           this.props = props;
        }
       function parent(props){ 
           this.props = props;             
           this.dataFromChild = null;
           this.getChildData = (data)=>{
                console.log('這個函數被運行了,我們拿到了傳過來的參數:'+data);
                this.dataFromChild = data;
           }
           this.childNodes  = new child({
                getChildData:this.getChildData
            }); 
        }
       console.log(new parent('這是一個屬性'));   
(別偷懶!f12,復制上述代碼到控制台運行!)
好的,簡單說下上述代碼做出的更改: 
1  父函數中定義了一個函數,通過參數對象(實則就是props啊)傳遞給了子函數;
2  這個函數一旦被執行,會把參數data賦值給父函數中的實例屬性data;
3  子函數通過props接收到了這個函數,運行了它,並且把自己的data作為參數傳遞了進去;

ok,那么我們經過運行,發現控制台打印的內容:

哦!!!於是我們明白了,我們寫原生js的時候,就是通過:
在父函數中定義方法,通過參數傳遞給子函數,子函數調用這個方法並且把自己數據作為參數,那么父函數就可以通過形參拿到了~
什么?有點繞?那么說的再簡單點:
父函數的方法傳遞給子函數,被子函數傳參調用。
那么趕緊用內存不足的大腦思考思考react中是不是也可以啊?

        class Child extends React.Component{
            data =  '我是子組件中的data'
            render(){
                this.props.getChildData(this.data);
                return <div>我是Child組件</div>
            }
        }
       class Parent extends React.Component{
            childData=null
            getChildData = (data)=>{
                this.childData = data;
                 console.log(data);
            }
            render(){
                return <Child getChildData = { this.getChildData }  />
            }
        }
    console.log(<Parent  />)
 上面的代碼夠簡練了吧(比中指)!
 那么我們運行上述代碼發現——乖乖,真的拿到了~~這不還是一樣嗎?我們玩的不是react嗎?怎么成原生js 了啊?啥啊誰啊我在哪啊??

 實則所有單向數據流的js框架都可以通過上述的方式進行子組件向父組件的通信。
 非常好,現在我們來整理一下react的父子組件間通信規則: 
 *父傳子:  父組件通過props傳參唄……*
 *子傳父 : 父組件通過props傳參唄……*
 啥? 我寫重了? 
 (哼哼一聲我露出了鄙視的微笑,並在下面多寫了一行)
 ***子傳父完整版: 父組件中定義函數,通過props傳遞給子組件,子組件調用這個函數並傳參。***
嗯…經過思考,我們得出了這樣一個結論: 子傳父這樣的逆向通信,實際也是符合單向數據流的概念。無非就是把函數當做參數傳遞下去而已啊!!!(重點是這句啊~~~react中的逆向通信的方式和單向數據流完全不沖突啊~)

子傳父(逆向通信)的其他方式

  除開上面講過的 父組件中定義函數傳遞給子組件並被其調用 這種js通用方式,在react中我們還可以怎樣玩?
  在Vue,React中都有ref 這樣一個特殊的實例屬性。
  react中 ref 具備兩種作用: 
  1   標記dom的話,能獲取dom實例;
  2    標記子組件的話,能獲取子組件實例的所有數據(包括子組件的props,state,定義的方法,實例…)。
  那么也就是說,父組件通過this.ref就拿到子組件的任何數據了…就這么簡單啊。
  當然,依照react的尿性,文檔中特意提到了一點:不要輕易用這玩意啊,危險啊,別沖動啊小伙子們~
  事實上,經過react的版本變化,ref賦值目前有三種方式 :  字符串、回調、 CreateRef() //這個是16.3后的新增api
  迭代維護做的都很到位啊~ 憑啥只用在表單控件里啊~
  當然,關於ref的花式玩法我們會在本系列后面內容講到。

遠親組件的通信

  其實無論做react還是vue或者其他項目,我們必須要明確,寫的還是js。(這也是為什么我一直把原生和react放在一起講)
  那么遠親組件的通信,我們即時對react毫無了解,也能至少說出一萬種方式…
 例如: 
      1   通過緩存  :  組件A把數據存到緩存中,組件B就可以從中取出; 
      2   通過url  :  通過location對象拿到…; 
      3   通過與后端配合: 組件A把數據扔到接口里去,組件B可以從中拿到…;
  以上方式,我稱之為通過第三方媒介的形式。
  (插一句: 有木有覺得redux中store共享跟session級別緩存很類似?)
  也就是說,遠親組件的通信,我們拋開react去思考得出一個結論:
  ——通過第三方媒介作為一個存儲地點,實現數據共享。
 
   ok我們把話題轉回來。react中,同系遠親的話(太太爺爺到重重孫子),完全可以通過context嘛(上一篇有講,后面也會出context的專章)…
   至於不是很遠的關系, 利用props一層一層往內傳啊。 (例如爺爺傳到孫子)
   
   逆向: 子調用爺爺的函數並傳參就實現了子傳爺爺;
   同級 : 子1傳父,父傳子2 ; 
   很遠關系: 1 context(自己實現試試啊~)  2 通過第三方媒介共享( 緩存,url,服務端,以及后面我們會講到的redux,react-redux,dva等全局狀態存儲管理插件);
   我們發現,就單單react的話,傳來傳去還是 父傳子 子傳父啊……最多特殊情況用到context(無論多遠的關系,最終肯定有個統一的祖宗啊<App ==!/>)而已啊~

總結

   這章講述了react的基礎必面的面試題:
   如何在react項目中實現組件間的通信。
   也可能會引發一些react與項目與原生的思考(這是我想要的)。
   

   如果本章內容對您有幫助,請點個推薦哦~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM