React.createContext

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ù)傳遞


image.png
使用:

如果要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>
    );
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容