React context基本用法

看風景就發表於2018-08-21

React的context就是一個全域性變數,可以從根元件跨級別在React的元件中傳遞。React context的API有兩個版本,React16.x之前的是
老版本的context,之後的是新版本的context。

1.老版本的context

getChildContext 根元件中宣告,一個函式,返回一個物件,就是context
childContextTypes 根元件中宣告,指定context的結構型別,如不指定,會產生錯誤
contextTypes 子孫元件中宣告,指定要接收的context的結構型別,可以只是context的一部分結構。contextTypes 沒有定義,context將是一個空物件。
this.context 在子孫元件中通過此來獲取上下文
(注:從React v15.5開始 ,React.PropTypes 助手函式已被棄用,可使用 prop-types 庫 來定義contextTypes)

舉例如下:

//根元件
class MessageList extends React.Component {
  getChildContext() {
    return {color: "purple",text: "item text"};
  }

  render() {
    const children = this.props.messages.map((message) =>
      <Message text={message.text} />
    );
    return <div>{children}</div>;
  }
}

MessageList.childContextTypes = {
  color: React.PropTypes.string
  text: React.PropTypes.string
};

//中間元件
class Message extends React.Component {
  render() {
    return (
      <div>
        <MessageItem />
        <Button>Delete</Button>
      </div>
    );
  }
}

//孫元件(接收元件)
class MessageItem extends React.Component {
  render() {
    return (
      <div>
        {this.props.text}
      </div>
    );
  }
}

MessageItem.contextTypes = {
  text: React.PropTypes.string
};

class Button extends React.Component {
  render() {
    return (
      <button style={{background: this.context.color}}>
        {this.props.children}
      </button>
    );
  }
}

Button.contextTypes = {
  color: React.PropTypes.string
};

2.新版本的context

新版本的React context使用了Provider和Customer模式,和redux-react的模式非常像。在頂層的Provider中傳入value,
在子孫級的Consumer中獲取該值,並且能夠傳遞函式,用來修改context,如下程式碼所示:

//建立Context元件
const ThemeContext = React.createContext({
  theme: 'dark',
  toggle: () => {}, //向上下文設定一個回撥方法
});

//執行APP
class App extends React.Component {
  constructor(props) {
    super(props);

    this.toggle = () => { //設定toggle方法,會作為context引數傳遞
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };

    this.state = {
      theme: themes.light,
      toggle: this.toggle,
    };
  }

  render() {
    return (
      <ThemeContext.Provider value={this.state}> //state包含了toggle方法
        <Content />
      </ThemeContext.Provider>
    );
  }
}

//中間元件
function Content() {
  return (
    <div>
      <Button />
    </div>
  );
}

//接收元件
function Button() {
  return (
    <ThemeContext.Consumer>
      {({theme, toggle}) => (
        <button
          onClick={toggle} //呼叫回撥
          style={{backgroundColor: theme}}>
          Toggle Theme
        </button>
      )}
    </ThemeContext.Consumer>
  );
}

詳細用法可以參考官方文件:https://react.docschina.org/docs/context.html#reactcreatecontext

3. context在如下的生命週期鉤子中可以使用

constructor(props, context)
componentWillReceiveProps(nextProps, nextContext)
shouldComponentUpdate(nextProps, nextState, nextContext)
componentWillUpdate(nextProps, nextState, nextContext)
componentDidUpdate(prevProps, prevState, prevContext)

4. 在無狀態元件中可以通過引數傳入

function D(props, context) {
  return (
    <div>{this.context.user.name}</div>
  );
}

D.contextTypes = {
  user: React.PropTypes.object.isRequired
}

5. React context的侷限性

1. 在元件樹中,如果中間某一個元件 ShouldComponentUpdate returning false 了,會阻礙 context 的正常傳值,導致子元件無法獲取更新。
2. 元件本身 extends React.PureComponent 也會阻礙 context 的更新。

注意點:

1. Context 應該是唯一不可變的
2. 元件只在初始化的時候去獲取 Context

 

參考:https://www.tuicool.com/articles/nUryimf
     https://segmentfault.com/a/1190000012575622

相關文章