[譯]遷移到新的 React Context Api

來源:互聯網
上載者:User

標籤:dcom   sum   添加   getch   不能   extends   status   create   const   

隨著 React 16.3.0 的發布,context api 也有了很大的更新。我已經從舊版的 api 更新到了新版。這裡就分享一下我(作者)的心得體會。

回顧

下面是一個展示如何使用舊版 api 的例子:

function Usage(props) {  return (    <Toggle onToggle={props.onToggle}>      <Toggle.On>The button is on</Toggle.On>      <Toggle.Off>The button is off</Toggle.Off>      <div>        <Toggle.Button />      </div>    </Toggle>  )}

上面的代碼會返回一個複合組件Toggle。這個組件可以讓子組件共用隱式的狀態。在某些簡單的情況下可以用React.Children.map來處理。但是,這個例子需要使用 context api 來達到在 React 的某個組件樹的任意節點分享 state 的目的。

舊的 Context Api

這是一箇舊版 context api 的應用例子:

const TOGGLE_CONTEXT = "__toggle__";// Toggle onfunction ToggleOn({ children }, context) {  const { on } = context[TOGGLE_CONTEXT];  return on ? children : null;}ToggleOn.contextTypes = {  [TOGGLE_CONTEXT]: PropTypes.object.isRequired};// Toggle offfunction ToggleOff({ children }, context) {  const { on } = context[TOGGLE_CONTEXT];  return on ? null : children;}ToggleOff.contextTypes = {  [TOGGLE_CONTEXT]: PropTypes.object.isRequired};// Toggle buttonfunction ToggleButton(props, context) {  const { on, toggle } = context[TOGGLE_CONTEXT];  return <Switch on={on} onClick={toggle} {...props} />;}ToggleButton.contextTypes = {  [TOGGLE_CONTEXT]: PropTypes.object.isRequired};// Toggleclass Toggle extends React.Component {  static On = ToggleOn;  static Off = ToggleOff;  static Button = ToggleButton;  static defaultProps = { onToggle: () => {} };  static childContextTypes = {    [TOGGLE_CONTEXT]: PropTypes.object.isRequired  };  state = { on: false };  toggle = () =>    this.setState(      ({ on }) => ({ on: !on }),      () => this.props.onToggle(this.state.on)    );  getChildContext() {    return {      [TOGGLE_CONTEXT]: {        on: this.state.on,        toggle: this.toggle,      }    };  }  render(){    return <div>{this.props.children</div>  }}

在就的 API 裡,你必須用一個字串指定要分享的 state。然後通過getChildContext方法返回實際的 context。在父組件裡通過childContextTypes來指定發出的 context 的類型,在子組件裡用contextTypes來指定接收的 context 的類型。我(作者, 下文同)從來不喜歡這樣不直接的方式, 平時也盡量不這麼做。另外,還要使用靜態屬性,才能保證 context 值傳入子組件。 我也不喜歡這樣。

另一個問題是如果shouldComponentUpdate方法返回 false 的話,context 的值是不會變的。當然這也有變通的方法,具體可以參考這個repo。

新的 Context API

新的 context api 沒有這些問題,這也是我為什麼這麼激動的原因。上面的例子可以更新為:

const ToggleContext = React.createContext({  on:false,  toggle: () => {},});class Toggle extends React.Component {  static On = ({children}) => (    <ToggleContext.Consumer>      {({on})=>(on ? children: null)}    </ToggleContet.Consumer>  )  static Off = ({children}) => (    <ToggleContext.Consumer>      {({on}) => (on ? null : children)}    </ToggleContext.Consumer>  );  static Button = props => (    <ToggleContext.Consumer>      {({on, toggle}) => (        <Switch on={on} toggle={toggle} {...props} />      )}    </ToggleContext.Consumer>  )  toggle = () => this.setState(    ({on}) => ({on: !on}),    () => this.props.onToggle(this.state.on)  );  state = {on: false, toggle: this.toggle};  render() {    return (      <ToggleContext.Provider value={}>        {this.props.children}      </ToggleContext.Provider>    );  }}

舊的API的問題都沒有了。現在不僅沒有了不直接的字串,還有了明顯的組件:ProviderConsumer分別提供和消費context。
每一個子組件都需要用consumer子組件,就想在就api裡需要有靜態屬性一樣)。但是,兩個api的這個問題都可以通過基於render props的高階組件來解決。非常簡單!

另一個通過shouldComponentUpdate返回false來更新的問題也解決了。新的context api會自動處理這個問題。

最後一個非常好的改變是子組件都使用了render props模式。這樣在新的context api裡也可以對外界暴露非常優雅的介面。

新api的問題

這就是在新的api裡通過Provider的value屬性給子組件消費的值,只有在你想要子組件重繪的時候才會改變。
這也就是說在render方法裡使用`value={{on: this.state.on, toggle: this.toggle}}是不被推薦的。
這是因為沒次render都會傳入一個新的對象,即使state本身沒有改變。
因為是一個新的對象,那麼所有的子組件也都會重繪。

這個影響在實際使用的時候會很大。一般來說最好是傳入一個只有在state改變時才改變的值。也就是為什麼說value={this.state}
如果你不想傳入整個state給消費者,那麼你可以使用這個Ryan Florence的這個小技巧。

只不過這也還是會有一個小問題,我需要把toggle方法存入state裡。這也顯得很奇怪,不過這隻是一個小瑕疵,不影響大局。

總結

新的context api絕對是React團隊帶來的一個非常好的改變。希望你也能和我一樣的喜歡。

另外:如果你還不能用16.3.0這個版本,那麼你可以添加一個polyfill來使用新的api。這個polyfill是create-react-context。

from:https://blog.kentcdodds.com/migrating-to-reacts-new-context-api-b15dc7a31ea0

[譯]遷移到新的 React Context Api

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.