React 通過context(上下文)實現多組件嵌套傳值的實現


在React當中,父組件通過props給子組件傳遞屬性的,但是當組件的嵌套層次非常多的時候,使用props傳參就不是很方便了,此時可以用context來實現。類似於Vue里的provide/inject這一對選項組,實現的效果是一樣的。

React里的context只能由class組件來提供,然后class組件內的子組件就可以獲取了,React里的conetxt有兩種使用方法:

  • childContextType  ;經典的用法,相比較第二種方法性能不是很好
  • createContext    ;React16提供的一個新的API,通過組件來實現的,效率比較高,推薦使用這個

方法一 childContextType使用方法

在父組件中,我們要提供一個getChildContext方法,用於指定子節點能獲取到的所有數據對象,還要在class對象上設置一個childContextTypes屬性,用於指定數據的類型,例如:

class Parent extends React.Component{
    getChildContext(){                                        //定義一個getChildContext成員函數,返回Parent組件提供的數據
        return {height:180}                                
    }
    render(){
        return <div>子節點jsx</div>
    }
}

Parent.childContextTypes = {                     //設置childContextTypes屬性,用於指定getChildlContext里返回的每個鍵的類型
    height:PropTypes.number
}

 writer by:大沙漠 QQ:22969969

在組件中,我們在class對象里設置一個contextTypes屬性即可,用於指定需要從父節點獲取的context,可以通過this.context獲取到所有能獲取到的context對象,例如:

class Child extends React.Component{
    render(){
        return <div>{this.context.height}</div>
    }
}
Child.contextTypes={                                 //設置contextTypes屬性,這里是子組件希望從父層組件提供的context中某幾個屬性
    height:PropTypes.number
}

使用這種方法時,需要加載一個prop-types.js文件,和聲明時的類型有關,script標簽可以直接用這個:https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.min.js,。

舉個例子:

<div id="root"></div>    
<script type="text/babel">
    class Parent extends React.Component{
        state = {height:180}
        getChildContext(){                                //這里提供給子組件中可以獲取的對象
            return {height:this.state.height}
        }                
        render(){
            return (
                <div>
                    <button  onClick={e=>this.setState({height:this.state.height+1})}>測試</button>
                    <Child></Child>
                </div>
            )
        }
    }
    Parent.childContextTypes = {        
        height:PropTypes.number
    }
    
    class Child extends React.Component{
        render(){
            return <p>{this.context.height}</p>
        }
    }
    Child.contextTypes = {                
        height:PropTypes.number
    }

    ReactDOM.render(<Parent></Parent>,root)
</script>

我們在Parent組件上定義了一個button按鈕,點擊時會使當前的state.height+1,然后又引用了Child子組件,通過childContextType進行了值的傳遞,渲染如下:

方法二 createContext方法

 這種方法是通過React16新增的一個API叫做React.createContext()來實現的,我們調用React.createContext時可以傳入一個參數,參數就是默認值,返回一個對象,含有一個Provider組件和一個Consumer組件,在需要使用context(上下文)的地方直接使用即可。

React.createContext()返回一個包含Provider和Consumer組件引用的對象,我們在需要提供數據的class組件內使用Provider組件(例如上面的Parent組件),在需要獲取數據的子組件內(例如上面的Child組件),直接使用context組件即可,Provider和Consumer組件的用法如下:

  1. Provider組件     ;給該組件傳遞一個value屬性,用於指定當前提供的數據,數據可以是任意值,數字、字符串、對象都可以
  2. Consumer組件   ;我們在顯示數據的地方直接使用即可,該組件的子節點是一個函數模板,React內部會直接執行該函數,參數就是傳遞的值。

 我們把例1里的例子重新用createContext來寫一下,如下:

<div id="root"></div>    
<script type="text/babel">
    const { Provider, Consumer } = React.createContext()           //調用React.createContext返回一個Provider和Consumer組件
    class Parent extends React.Component{
        state = {height:180}
        render(){                        
            return (
                <div>
                    <button  onClick={e=>this.setState({height:this.state.height+1})}>測試</button>
                    <Provider value={{height:this.state.height}}>         //Provider組件內通過value設置contexxt
                        <Child></Child>
                    </Provider>
                    
                </div>
            )
        }
    }

    class Child extends React.Component{
        render(){
            return     <p>
                                <Consumer>{val=>val.height}</Consumer>          /子組件內通過Consumer來直接獲取值,子節點是一個函數,參數是傳遞過來的值
                            </p>
        }
    }

    ReactDOM.render(<Parent></Parent>,root)
</script>

實現的效果和例1是一樣的,就不截圖演示了。

用childContextType實現時,如果getChildContext內返回的一個值改變了,所有的子節點都將重新渲染,而用createContext實現時,如果改變了某個數據,只有引用數據的那個DOM節點對象才會重新渲染,其它DOM並不會更新,因此性能更好一點。

官方說childContextType在React17中將被淘汰,如果淘汰了那么function組件和class組件的參數2不就沒什么含義了么(因為這個參數2是可以獲取到的所有的context集合),如果通過createContext來獲取的話性能又和getChildContext一樣了,以后回來再看看將來會怎么實現。

 writer by:大沙漠 QQ:22969969

 


免責聲明!

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



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