上下文(Context) 提供了在組件之間共享這些值的方法,而沒必要在樹的每一個層級顯式傳遞一個 prop 。javascript
通常狀況下,在你沒有絕對把握用好和必須的場景下,是不推薦使用的。java
可是咱們依然間接的使用着它,好比許多官方依賴在使用,如:react-redux, mobx-react,react-router。咱們須要它功能的時候,更可能是靠第三方依賴庫就能實現,而不是本身手動寫context。可是,依然須要理解它,對用它的一些依賴庫源碼理解頗有幫助。react
import React, { Component } from 'react'; class Grandpa extends Component { state = { info: 'GrandPa組件的信息' } render() { return ( <div> <Father info={this.state.info}/> </div> ); } } class Father extends Component { render() { return ( <div> <Son info={this.props.info}/> </div> ); } } class Son extends Component { render() { return ( <div> 我是Son組件,拿到信息爲:{this.props.info} </div> ); } } export default Grandpa;
最後頁面輸出:redux
我是Son組件,拿到信息爲:GrandPa組件的信息
咱們會發現這樣的缺點是一層一層傳值,若是有更多層級和更多數據的話,會讓代碼看起來很不整潔,若是中間哪一個組件忘了傳值基本就完了;並且Father組件也並無用到info值,只是將值傳給Son組件。api
若是使用context,就能幫咱們解決這個層級不停傳值的問題。react-router
context有舊版和新版之分,以React v16.3.0版本劃分。ide
咱們先來講下舊版context API函數
將代碼改爲以下:this
import React, { Component } from 'react'; import PropTypes from 'prop-types'; class Grandpa extends Component { state = { info: 'GrandPa組件的信息' } getChildContext () { return { info: this.state.info } } render() { return ( <div> <Father/> </div> ); } } // 聲明Context對象屬性 Grandpa.childContextTypes = { info: PropTypes.string } class Father extends Component { render() { return ( <div> <Son/> </div> ); } } class Son extends Component { render() { return ( <div> 我是Son組件,拿到信息爲:{this.context.info} </div> ); } } // 根據約定好的參數類型聲明 Son.contextTypes = { info: PropTypes.string } export default Grandpa;
對PropTypes類型檢查,還能夠寫成下面這種寫法code
class Grandpa extends Component { static childContextTypes = { info: PropTypes.string } state = { info: 'GrandPa組件的信息' } getChildContext () { return { info: this.state.info } } render() { return ( <div> <Father/> </div> ); } }
在須要傳出去的context值和須要接收context值都要進行類型檢查判斷。
正經常使用這個api可能沒什麼問題,但若是中間哪一個組件用到shouldComponentUpdate
方法的話,就極可能出現問題。
三個組件的層級關係以下
<GrandPa> <Father> <Son/> </Father> </GrandPa>
若是在GrandPa組件設置按鈕點擊能夠更新info的值,即經過this.setState({info: '改變值'})
方法
更新 Context:
那麼
假如在Father組件添加函數
shouldComponentUpdate () { return false }
因爲Father並不依賴任何值,因此咱們默認讓它無需從新render。可是,這會致使Son組件也不會從新render,即沒法獲取到最新的 Context 值。
這樣的不肯定性對於目標組件來講是徹底不可控的,也就是說目標組件沒法保證本身每一次均可以接收到更新後的 Context 值。這是舊版API存在的一個大問題。
而新版API解決了這個問題,咱們來看下新版API怎麼寫的
新版Context 新增了 creactContext() 方法用來建立一個context對象。這個對象包含兩個組件,一個是 Provider(生產者),另外一個是 Consumer(消費者)。
React.createContext 方法用於建立一個 Context 對象。該對象包含 Provider 和 Consumer兩個屬性,分別爲兩個 React 組件。
const InfoContext = React.createContext('');
class Grandpa extends Component { state = { info: 'GrandPa組件的信息' } render() { return ( <InfoContext.Provider value={{ info: this.state.info }}> <Father/> </InfoContext.Provider> ); } }
class Son extends Component { render() { return ( <InfoContext.Consumer> { value => { return <div>我是Son組件,拿到信息爲:{value.info}</div> } } </InfoContext.Consumer> ); } }