關於react-context的官方文檔
https://reactjs.org/docs/context.htmlhtml
不少同窗認爲一旦父子組件之間層級過深,多層級通信時候第一反應就是要用vuex和redux,但每每殺雞用了宰牛刀。可是vue和react中提供了不少方法去達到數據共享的效果,而沒必要顯式地經過組件樹的逐層傳遞 props。
好比在vue中provide 和 inject前端
一、這對選項須要一塊兒使用,以容許一個祖先組件向其全部子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。
二、provide提供數據,多層子組件 向上層尋找,只要找到 就不在向上層尋找了。
三、inject 向子組件注入數據;
vue中的mixin和extend也能夠作到相關功能,這裏就不作詳細贅述,須要瞭解的同窗能夠自行去觀看。
下面回到本篇文章的正題react-context,React官網的高級指引中指出了Context,優雅的解決這個問題。vue
前端同窗都知道在js中的context指的是執行上下文,this指向誰,誰就是當前的執行上下文。react
Context 提供了一個無需爲每層組件手動添加 props,就能在組件樹間進行數據傳遞的方法。
意思即是context可以沒必要顯式地經過組件樹的逐層傳遞 props,能夠跨層級進行數據傳遞。vuex
先簡單說下老版本,以前也是實驗性的存在,我以爲不太好用。生產者須要聲明childContextTypes對象,對類數據類型進行校驗,不提供就會報錯。
具體的就不細說,須要瞭解的同窗自行查看。redux
學習context首先須要瞭解其三個核心的api: React.createContext()、Provider(發佈者)、Consumer(訂閱者)api
createContext()建立一個 Context 對象。瀏覽器
每一個 Context 對象都會返回一個 Provider React 組件,它容許消費組件訂閱 context 的變化。ide
Provider 接收一個value
屬性,傳遞給消費組件。一個 Provider 能夠和多個消費組件有對應關係。多個 Provider 也能夠嵌套使用,裏層的會覆蓋外層的數據。函數
當 Provider 的value
值發生變化時,它內部的全部消費組件都會從新渲染。Provider 及其內部 consumer 組件都不受制於shouldComponentUpdate
函數,所以當 consumer 組件在其祖先組件退出更新的狀況下也能更新。
value的值天然是能夠動態變動的,而且會傳遞給子組件中,點擊變動value按鈕會發現頁面上的三個tomorrow變爲三個yesterday。
import React, { useContext } from 'react' const ThemeContext = React.createContext('today') class App extends React.Component { state = { user: 'tomorrow' } change = () => { this.setState({ user: 'yesterday' }) } render() { const { user } = this.state // createContext默認值是「today」。 // 不管多深,任何組件都能讀取這個值。 // 這裏Provider 把value值 「tomorrow」 做爲當前的值傳遞下去。 return ( <ThemeContext.Provider value={ user }> <div onClick={ this.change }>變動value</div> <Toolbar /> </ThemeContext.Provider> ); } }
這裏是react-hook函數式寫法,用到react-hook的API:useContext獲取context的值
掛載在 class 上的contextType
屬性會被重賦值爲一個由React.createContext()
建立的 Context 對象。這能讓你使用this.context
來消費最近 Context 上的那個值。你能夠在任何生命週期中訪問到它,包括 render 函數中
function Toolbar() { const context = useContext(ThemeContext) return ( <div> <div>{context}</div> <Head /> </div> ); }
經過ThemeContext的屬性Consumer消費用戶數據
Consumer的子組件必須是一個function,經過function的參數接收頂層傳入的數據
任何訂閱者(Consumer)均可以直接修改context,這會致使後續的訂閱者獲取到修改後的context值,但這顯然是不可取的。
若是須要修改,應該統一由發佈者(Provider)修改,也就是相似APP組件中變動value按鈕
class Head extends React.Component { render() { return ( <ThemeContext.Consumer> { context => ( <div> <div>{this.context}</div> <Title /> </div> ) } </ThemeContext.Consumer> ) } }
最後的子組件顯示context內容
context還有個Api:Context.displayName
想了解的同窗能夠去官網看一下
class Title extends React.Component { static contextType = ThemeContext render() { return ( <div> {this.context} </div> ) } }
在 provider 的父組件進行重渲染時,可能會在 Consumers 組件中觸發意外的渲染。
下面例子:對value直接賦值的時候就會觸發這種沒必要要的渲染
const ThemeContext = React.createContext(); class App extends React.Component { render() { return ( <ThemeContext.Provider value={ {name: '666'} }> <div onClick={ this.change }>變動value</div> <Toolbar /> </ThemeContext.Provider> ); } }
能夠經過把value值放在state中解決這種問題
const ThemeContext = React.createContext(); class App extends React.Component { state = { name: '666' } change = () => { this.setState({ user: 'yesterday' }) } render() { const { user } = this.state return ( <ThemeContext.Provider value={ user }> <div onClick={ this.change }>變動value</div> <Toolbar /> </ThemeContext.Provider> ); } }
有沒有發現redux的注入和context的注入很是類似。
經過React Developer Tools在瀏覽器很容易發現
react-redux其實是經過Provider組件和connect方法進行鏈接react和redux,那麼他們到底本質上就是經過Context來傳遞數據
以上就是我的對react-context學習的一點總結。context雖然輕便,可是官方仍是沒有大面積的去推廣,仍是存在些問題,畢竟和強大的react-redux對比,沒有很好的管理體系,普遍認知度也比較低。可是凡事沒有絕對好壞,只有適不適合。