React context 理解

關於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

context含義

前端同窗都知道在js中的context指的是執行上下文,this指向誰,誰就是當前的執行上下文。react

而react-context是什麼呢?react-context官網中第一句就給出瞭解釋:

Context 提供了一個無需爲每層組件手動添加 props,就能在組件樹間進行數據傳遞的方法。
意思即是context可以沒必要顯式地經過組件樹的逐層傳遞 props,能夠跨層級進行數據傳遞。vuex

其實質爲跨層級的組件搭建一座橋樑。

context Api

React context的API有兩個版本,React16.x以前的是老版本的context,以後的是新版本的context。

先簡單說下老版本,以前也是實驗性的存在,我以爲不太好用。生產者須要聲明childContextTypes對象,對類數據類型進行校驗,不提供就會報錯。
具體的就不細說,須要瞭解的同窗自行查看。redux

下面回到16.x版本的context,Context是16.3.0正式肯定的API

學習context首先須要瞭解其三個核心的api: React.createContext()、Provider(發佈者)、Consumer(訂閱者)api

React.createContext()和Provider

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>
  );
}

Consumer

經過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>
    );
  }
}

似曾相識的context -- redux

有沒有發現redux的注入和context的注入很是類似。
image.png
經過React Developer Tools在瀏覽器很容易發現
react-redux其實是經過Provider組件和connect方法進行鏈接react和redux,那麼他們到底本質上就是經過Context來傳遞數據
WeChatb37598c11cb3bb30ffb2ac7bd28f063c.png

以上就是我的對react-context學習的一點總結。context雖然輕便,可是官方仍是沒有大面積的去推廣,仍是存在些問題,畢竟和強大的react-redux對比,沒有很好的管理體系,普遍認知度也比較低。可是凡事沒有絕對好壞,只有適不適合。

相關文章
相關標籤/搜索