Context被翻譯為上下文,在React的官方文檔中歸類于高級部分,屬于React的高級API,但官方并不建議在穩(wěn)定版的App中使用Context。
很多優(yōu)秀的React組件都通過Context來完成自己的功能,比如react-redux的<Provider />,就是通過Context提供一個(gè)全局態(tài)的store,拖拽組件react-dnd,通過Context在組件中分發(fā)DOM的Drag和Drop事件,路由組件react-router通過Context管理路由狀態(tài)等等
定義:
當(dāng)你不想在組件樹中通過逐層傳遞 props 或者 state 方法來傳遞數(shù)據(jù)時(shí),可以使用Context來實(shí)現(xiàn)跨層級的組件數(shù)據(jù)傳遞

使用:
如果要Context發(fā)揮作用,需要用到兩種組件,一個(gè)是Context生產(chǎn)者(Provider),通常是一個(gè)父節(jié)點(diǎn),另外是一個(gè)Context的消費(fèi)者(Consumer),通常是一個(gè)或者多個(gè)子節(jié)點(diǎn)。所以Context的使用基于生產(chǎn)者消費(fèi)者模式。
const ThemeContext = React.createContext('light'); // 創(chuàng)建
class App extends React.Component {
render() {
// 使用一個(gè) Provider 來將當(dāng)前的 theme 傳遞給以下的組件樹。
// 無論多深,任何組件都能讀取這個(gè)值。
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
// 中間的組件再也不必指明往下傳遞 theme 了。
function Toolbar(props) {
return (
<div>
<ThemedText />
</div>
);
}
class ThemedText extends React.Component {
// 指定 contextType 讀取當(dāng)前的 theme context。
// React 會(huì)往上找到最近的 theme Provider,然后使用它的值。
static contextType = ThemeContext;
render() {
return <div>{this.context}</div>;
}
}
API:
- React.createContext
cont MyContext = React.createContext(defaultValue);
創(chuàng)建一個(gè)context對象。組件會(huì)向組件所處的樹中距離最近的那個(gè)Provider進(jìn)行匹配context。
當(dāng)組件所處的樹沒有匹配到Provider (不使用Provider組件) 時(shí),defaultValue參數(shù)才會(huì)生效。
- Context.Provider
<MyContext.Provider value={/* 值 */}>
每個(gè) Context 對象都會(huì)返回一個(gè) Provider React 組件,它允許消費(fèi)組件訂閱 context 的變化。
Provider 接收一個(gè) value 屬性,傳遞給消費(fèi)組件。一個(gè) Provider 可以和多個(gè)消費(fèi)組件有對應(yīng)關(guān)系。多個(gè) Provider 也可以嵌套使用,里層的會(huì)覆蓋外層的數(shù)據(jù)。
當(dāng) Provider 的 value 值發(fā)生變化時(shí),它內(nèi)部的所有消費(fèi)組件都會(huì)重新渲染。Provider 及其內(nèi)部 consumer 組件都不受制于 shouldComponentUpdate 函數(shù),因此當(dāng) consumer 組件在其祖先組件退出更新的情況下也能更新。
- Class.contextType
class MyClass extends React.Component {
render() {
let value = this.context;
/* 基于 MyContext 組件的值進(jìn)行渲染 */
}
}
MyClass.contextType = MyContext;
// 或者像上面使用 static 定義靜態(tài)變量
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
}
}
掛載在 class 上的 contextType 屬性會(huì)被重賦值為一個(gè)由 React.createContext() 創(chuàng)建的 Context 對象。這能讓你使用 this.context 來消費(fèi)最近 Context 上的那個(gè)值。
注意:
你只通過該 API 訂閱單一 context。
你可以使用 public class fields 的static這個(gè)類屬性來初始化你的contextType。
- Context.Consumer
<MyContext.Consumer>
{value => /* 基于 context 值進(jìn)行渲染*/}
</MyContext.Consumer>
這種寫法也可以訂閱到 context,這需要函數(shù)作為子元素,這個(gè)函數(shù)接收當(dāng)前的context值。
- 對于 Provider 和 Consumer 可以這樣使用:
let { Provider, Consumer } = React.createContext();
<Provider value={this.state.value}>
// ...
</Provider>
<Consumer>
{ state => {
return <div> // ... </div>
}}
</Consumer>
但對于多個(gè)Context時(shí),這種方法就無法標(biāo)識(shí)是哪一個(gè)context,就需要在使用Provider和Consumer組件前調(diào)用所屬Context。
- 注意事項(xiàng):
在使用Provider時(shí),value值如果接收一個(gè)新建對象,每次重新渲染Provider時(shí),value屬性總會(huì)被賦值為新的對象:
class App extends React.Component {
render() {
return (
<Provider value={{something: 'something'}}>
<Toolbar />
</Provider>
);
}
}
解決這個(gè)問題,將value 狀態(tài)提升到父節(jié)點(diǎn)的state中:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}