跳转至

Context的用法

Context是用于解决组件层层传递参数的问题。

var Button = React.createClass({
  render: function() {
    return (
      <button style={{background: this.props.color}}>
        {this.props.children}
      </button>
    );
  }
});

var Message = React.createClass({
  render: function() {
    return (
      <div>
        {this.props.text} <Button color={this.props.color}>Delete</Button>
      </div>
    );
  }
});

var MessageList = React.createClass({
  render: function() {
    var color = "purple";
    var children = this.props.messages.map(function(message) {
      return <Message text={message.text} color={color} />;
    });
    return <div>{children}</div>;
  }
});

上面的代码需要层层传递color参数,这很不方便。context属性可以解决这个问题。

首先,改写根组件。

var MessageList = React.createClass({
  childContextTypes: {
    color: React.PropTypes.string
  },
  getChildContext: function() {
    return {color: "purple"};
  },
  render: function() {
    var children = this.props.messages.map(function(message) {
      return <Message text={message.text} />;
    });
    return <div>{children}</div>;
  }
});

上面代码中,根组件添加childContextTypesgetChildContext属性,React自动将context信息传向子树上的所有组件。

然后,子组件获取context属性。

var Button = React.createClass({
  contextTypes: {
    color: React.PropTypes.string
  },
  render: function() {
    return (
      <button style={{background: this.context.color}}>
        {this.props.children}
      </button>
    );
  }
});

子组件通过定义contextTypes属性,可以获取context对象上的信息。如果contextTypes属性没有定义,那么this.context将是一个空对象。

如果组件内部定义了contextTypes方法,那么生命周期方法会接收到一个额外的参数context对象。

void componentWillReceiveProps(
  object nextProps, object nextContext
)

boolean shouldComponentUpdate(
  object nextProps, object nextState, object nextContext
)

void componentWillUpdate(
  object nextProps, object nextState, object nextContext
)

void componentDidUpdate(
  object prevProps, object prevState, object prevContext
)

无状态的函数组件也能够引用context对象,如果contextTypes被定义成函数的一个属性。

function Button(props, context) {
  return (
    <button style={{background: context.color}}>
      {props.children}
    </button>
  );
}
Button.contextTypes = {color: React.PropTypes.string};

只要stateprops发生变化,getChildContext就会被调用。后代组件就会接收到一个新的context对象。

var MediaQuery = React.createClass({
  getInitialState: function(){
    return {type:'desktop'};
  },
  childContextTypes: {
    type: React.PropTypes.string
  },
  getChildContext: function() {
    return {type: this.state.type};
  },
  componentDidMount: function(){
    var checkMediaQuery = function(){
      var type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';
      if (type !== this.state.type){
        this.setState({type:type});
      }
    };

    window.addEventListener('resize', checkMediaQuery);
    checkMediaQuery();
  },
  render: function(){
    return this.props.children;
  }
});

context属性有点像全局变量,轻易不能使用,你应该宁可将参数一层层显式传给子组件。

最佳的使用场合是传递用户的语言选择、样式选择,否则这些值就要被当作全局变量传入组件。

不要使用context将你的Modal数据传给组件。显式传递更容易理解。使用context将造成组件的强耦合,代码难以复用。