React Context 理解和使用


寫在前面

​ 鑒於筆者學習此內容章節 React官方文檔 時感到閱讀理解抽象困難,所以決定根據文檔理解寫一篇自己對Context的理解,文章附帶示例,以為更易於理解學習。更多內容請參考 React官方文檔

​ 如果您覺得文章對您有幫助,可以點擊文章右下角【推薦】一下。您的鼓勵是筆者創作的最大動力!

​ 如果發現文章有問題也可以在文章下方及時聯系筆者哦,相互探討一起進步~

基本概念

  • ContextReact中為了避免在不同層級組件中逐層傳遞props的產物,在沒有Context的時候父組件向子組件傳遞props屬性只能在組件樹上自上而下進行傳遞,但是有些屬性並不是組件樹的每層節點都有相同的需求,這樣我們再這樣逐層傳遞props就顯得代碼很繁瑣笨重。
  • 使用React.createContext(defulData)可以通過創建一個ContextObject,在某個組件中調用ContextObject.Provider同時可以設置新的value = newData覆蓋掉defulData共享到下面的所有子組件,需要ContextObject共享出來的數據的子組件可以通過static contextType = ContextObject接收到data,使用this.context即可調用data

適用場景

  • 很多不同層級的組件需要訪問同樣的數據,所以如果我們只是想避免層層傳遞一些屬性,那么我們還有更好的選擇: 組合組件(合理利用{props.children})

Context API 理解與運用

  • React.createContext(defaultValue)
    創建一個Context對象,defaultValue是默認參數,在一個組件中可以調用這個對象的ProviderAPI,並且設置新的參數:
const Context = React.createContext(defaultValue)
function ContextProvider () {
    return (
    	<Context.Provider value = { newValue }>
		  /* 子組件(這里的組件及其子組件都可以收到這個Context對象發出的newValue) */
		<Context.Provider/>
    )
}

​ 但是如果沒有對應的Context.Provider相匹配,那么組件樹上的所有組件都可以收到這個Context對象發出 的defaultValue

​ 同時可以調用ContextConsumerAPI可以用來接受到Context的值,並且根據這個值渲染組件:

function ContextConsumer () {
    return (
    	<Context.Comsumer>
            {value => 
            	<div>
            		/* 可以根據value進行渲染 */
        		</div>
            }
        </Context.Comsumer>
    )
}
  • Context.Provider & Context.Comsumer

    • <MyContext.Provider value={ variableValue }>可以允許消費組件訂閱到variableValue 值的變化,也就是說消費組件可以根據variableValue值的變化而變化,variableValue的值我們可以定義一個事件來控制改變;

    <MyContext.Consumer>
      {value => /* 基於 context 值進行渲染*/}
    </MyContext.Consumer>
    

    利用Context.Consumer API 可以讓我們即使是在函數式組件也可以訂閱到 Context的值;

    這種方法需要一個函數作為子元素,函數接收當前的context值,並返回一個 React 節點。

    傳遞給函數的 value 值等價於組件樹上方離這個 context 最近的 Provider 提供的 variableValue 值。如果沒有對應的 Provider,value 參數等同於傳遞給 createContext()defaultValue

    // Provider 結合 Consumer 使用示例
    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    // 創建 Context 對象
    const MyContext = React.createContext(0) // defaultValue 是數字0
    
    // App組件 渲染 Context 對象
    class App extends  React.Component {
        constructor(props){
            super(props);
            this.state = {
                variableValue : 0
            }
            // 處理 Provider中value變化的函數
            this.handleChange = () => {
                this.setState(state => ({
                    variableValue: state.variableValue + 1
                    })
                )
            }
        }
        render(){
            return (
                // 調用 Context.Provider, 設置可以讓Consumer組件監聽變化的 value 值
                    <MyContext.Provider value = {this.state.variableValue}>
                        <Context changeValue = {this.handleChange}/>
                    </MyContext.Provider>
            )
        }
    }
    // 消費組件
    class Context extends React.Component{
        render(){
            return (
                <MyContext.Consumer>
                    /* 根據Context的value進行渲染 */
                    {value =>
                            <button onClick={this.props.changeValue} >
                                Add MyValue:{value}
                            </button>
                    }
                </MyContext.Consumer>
            )
        }
    }
    ReactDOM.render(
            <App className = 'app'/>
    ,
      document.getElementById('root')
    );
    

    當Provider的 variableValue值發生變化時,它內部的所有消費組件都會重新渲染。

  • Class.contextType

    class MyClass extends React.Component {
      render() {
        let value = this.context; // this.context 可以訪問到 MyClass 的contextType
        /* 基於 MyContext 組件的值進行渲染 */
      }
    }
    MyClass.contextType = MyContext; //將MyClass的contextType屬性賦值為 Context 對象的值
    

    掛載在 class 上的 contextType 屬性會被重賦值為一個由 React.createContext() 創建的 Context 對象。此屬性能讓你使用 this.context 來消費最近 Context 上的那個值。你可以在任何生命周期中訪問到它,包括 render 函數中。

    注: 從文檔的字面意思,Class.contextType類組件特有的API,所以函數式組件只能使用 Context.Consumer來訪問 Context對象的值,我們可以來試一下類組件和函數式組件的API:

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    // 創建 Context 對象
    const MyContext = React.createContext(0)
    // App組件 渲染 Context 對象
    class App extends  React.Component {
        constructor(props){
            super(props);
            this.state = {
                variableValue : 0
            }
            this.handleChange = () => {
                this.setState(state => ({
                    variableValue: state.variableValue + 1
                    })
                )
            }
        }
        render(){
            return (
                // 調用 Context.Provider, 設置可以讓Consumer組件監聽變化的 value 值
                    <MyContext.Provider value = {this.state.variableValue}>
                        <Context_consumer changeValue = {this.handleChange} />
                        <br/>
                        <Context_contextType changeValue = {this.handleChange} />
                        <br />
                        <Func_Consumer changeValue = {this.handleChange} />
                        <br />
                        <func_contextType changeValue = {this.handleChange} />
                    </MyContext.Provider>
            )
        }
    }
    // Class & Consumer 消費組件
    class Context_consumer extends React.Component{
        render(){
            return (
                <MyContext.Consumer>
                    {value =>
                            <button onClick={this.props.changeValue} >
                                Add Class_consumer:{value}
                            </button>
                    }
                </MyContext.Consumer>
            )
        }
    }
    // Class & contextType 的消費組件
    class Context_contextType extends React.Component{
        render(){
            let value = this.context
            return (
                        <button onClick={this.props.changeValue} >
                            Add Class_contextType:{value}
                        </button>
            )
        }
    };
    Context_contextType.contextType = MyContext;
    // 函數組件 & Consumer
    function Func_Consumer (props) {
        return (
            <MyContext.Consumer>
                {value =>
                    <button onClick={props.changeValue} >
                        Add Func_consumer:{value}
                    </button>
                }
            </MyContext.Consumer>
        )
    }
    
    // 函數組件 & contextType
    function func_contextType (props) {
        let value = this.context
        return (
            <button onClick={props.changeValue} >
                Add func_contextType:{value}
            </button>
        )
    }
    func_contextType.contextType = MyContext;
    
    ReactDOM.render(
            <App className = 'app'/>
    ,
      document.getElementById('root')
    );
    
    

    運行結果:
    除了func_contextType組件之外其他組件都可以正常運行
    avatar

  • Context.displayName

    context 對象接受一個名為 displayName 的 property,類型為字符串。React DevTools 使用該字符串來確定 context 要顯示的內容。

    示例,下述組件在 DevTools 中將顯示為 MyDisplayName:

    const MyContext = React.createContext(/* some value */);
    MyContext.displayName = 'MyDisplayName';
    <MyContext.Provider> // "MyDisplayName.Provider" 在 DevTools 中
    <MyContext.Consumer> // "MyDisplayName.Consumer" 在 DevTools 中
    


免責聲明!

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



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