React+DvaJs 之 Context與Props

Context

React 遵循 Flux 思想進行數據流傳遞的時候,常見的方式是通過props 逐層從父級向子組件傳遞。

context 是實驗功能,可以簡化傳遞過程,尤其是組件樹層數很多的時候,但是不容易發現傳遞的流向,所以謹慎使用

傳統的props傳值

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

class Message extends React.Component {
  render() {
    return (
      <div>
        {this.props.text} <Button color={this.props.color}>Delete</Button>
      </div>
    );
  }
}

class MessageList extends React.Component {
  render() {
    const color = "purple";
    const children = this.props.messages.map((message) =>
      <Message text={message.text} color={color} />
    );
    return <div>{children}</div>;
  }
}

這個例子中,就是從Message 組件傳遞button組件的 color屬性來實現主題控制,整個傳遞過程有些繁瑣,如果使用context,代碼如下:

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

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

class Message extends React.Component {
  render() {
    return (
      <div>
        {this.props.text} <Button>Delete</Button>
      </div>
    );
  }
}

class MessageList extends React.Component {
  getChildContext() {
    return {color: "purple"};
  }

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

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

通過給MessageList 添加childContextTypesgetChildContext,可以自動在組件樹的運行上下文環境中傳遞值,作爲父級設置值的時候,父級組件只能以類的形式聲明,無狀態函數式聲明不可以。
子組件隨後就可以使用context獲取,但是必須定義 contextTypes,負責獲取的是空對象。組件的聲明就沒有父組件的限制,可以是無狀態函數式(stateless functional),或類。

各組件生命週期方法中的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樣例:

const Button = ({children}, context) =>
  <button style={{background: context.color}}>
    {children}
  </button>;

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

更新context

stateprops改變時會自動調用getChildContext,爲了更新context中的數據,可以使用this.setState來觸發局部state更新,這種更新會傳遞到所有子節點。

class MediaQuery extends React.Component {
  constructor(props) {
    super(props);
    this.state = {type:'desktop'};
  }

  getChildContext() {
    return {type: this.state.type};
  }

  componentDidMount() {
    const checkMediaQuery = () => {
      const type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';
      if (type !== this.state.type) {
        this.setState({type});
      }
    };

    window.addEventListener('resize', checkMediaQuery);
    checkMediaQuery();
  }

  render() {
    return this.props.children;
  }
}

MediaQuery.childContextTypes = {
  type: React.PropTypes.string
};

如果沒看懂或者有任何,可以看看facebook 原版文章,歡迎留言交流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章