聊一聊如何使用context,這是學習redux原始碼的基礎哦

Colin_Mindset發表於2019-03-05

在學習redux原始碼一段時間之後,我發現不懂得context如何使用已經阻礙到我理解redux的設計思想了。。
所以,這裡介紹一下react的context如何使用,不過這個api可能你在業務開發時永遠不會用到。。
好了,廢話不多說,我們來講解下context如何使用。

一. 如何使用context?

想象一下,我們有現在這樣一個頁面(Index),其元件樹長成如下這個樣子:
在這裡插入圖片描述
假設這個元件樹裡的任意一個元件都可以去更新Index中的屬性themeColor,這個時候就有了狀態提升的問題,需要把狀態提升到Index中,然後一級一級傳下來。
在這裡插入圖片描述
這裡的問題是非常明顯的,需要把狀態一級一級傳遞下去,如果元件層次很深的話,可維護性會非常非常差,簡直就是災難。
如果這棵元件樹長這個樣子就好了,所有元件可以去一個公共區域去獲取狀態,這樣不管元件層次有多深,每個元件都可以去這個公共區域去獲取狀態。
在這裡插入圖片描述
我們實現一下這個元件樹

class Index extends Component {
  render () {
    return (
      <div>
        <Header />
        <Main />
      </div>
    )
  }
}

class Header extends Component {
  render () {
    return (
    <div>
      <h2>This is header</h2>
      <Title />
    </div>
    )
  }
}

class Main extends Component {
  render () {
    return (
    <div>
      <h2>This is main</h2>
      <Content />
    </div>
    )
  }
}

class Title extends Component {
  render () {
    return (
      <h1>React.js 小書標題</h1>
    )
  }
}

class Content extends Component {
  render () {
    return (
    <div>
      <h2>React.js 小書內容</h2>
    </div>
    )
  }
}

ReactDOM.render(
  <Index />,
  document.getElementById('root')
)

接下來我們基於以上程式碼,來介紹如何使用context。

class Index extends Component {
  static childContextTypes = {
    themeColor: PropTypes.string
  }

  constructor () {
    super()
    this.state = { themeColor: 'red' }
  }

  getChildContext () {
    return { themeColor: this.state.themeColor }
  }

  render () {
    return (
      <div>
        <Header />
        <Main />
      </div>
    )
  }
}

先宣告一個靜態變數childContextTypes,這個變數名是固定的。然後,我們在state裡初始化一個狀態,然後在getChildContext(這個方法名也是固定的)裡設定context
以上操作,我們就完成了父元件的context設定工作,接下來,我們看下在子元件裡如何去取context

class Title extends Component {
  static contextTypes = {
    themeColor: PropTypes.string
  }

  render () {
    return (
      <h1 style={{ color: this.context.themeColor }}>React.js 小書標題</h1>
    )
  }
}

子元件要想獲得context,必須要宣告contextTypes,這個變數名也是固定的,必須要這樣寫。
接下來,我們就可以在子元件中通過this.context來獲取context中的值,可以在父元件中通過this.setState來修改context中的值。

二. 更直觀地使用context

在最近幾個版本中,React對contextapi進行了調整,更加明確了生產者消費者的使用方式。

import React from 'react';

const ThemeContext = React.createContext({
  themeColor: 'red',
});

通過靜態方法React.createContext建立一個context物件,這個context物件包含兩個元件:ProviderConsumer

class App extends React.Component {
  render () {
    return (
      <ThemeContext.Provider value={{themeColor: 'green'}}>
        <Header />
      </ThemeContext.Provider>
    );
  }
}

Providervalue相當於getChildContext()

class Header extends React.Component {
  render () {
    return (
      <Title>Hello React Context API</Title>
    );
  }
}
 
class Title extends React.Component {
  render () {
    return (
      <ThemeContext.Consumer>
        {context => (
          <h1 style={{background: context.themeColor}}>
            {this.props.children}
          </h1>
        )}
      </ThemeContext.Consumer>
    );
  }
}

Consumerchildren必須是一個函式,通過函式的引數獲取Provider提供的Context

三. 總結

新版本的react裡對contextapi調整過後,開發者能夠更加直觀地理解context的使用方式。

四. 參考

https://juejin.im/post/5a90e0545188257a63112977
https://www.jianshu.com/p/c7c47ead84c7
https://react.docschina.org/docs/context.html
https://yepbug.com/2018/11/11/react-context-and-simple-redux/
http://huziketang.mangojuice.top/books/react/lesson29

相關文章