React組件編寫思路(二)

上一篇講了 React 兩種最多見的組件:受控組件和非受控組件。爲了可用性,咱們通常編寫出來的組件但願支持這兩種特性:能夠經過組件自身的方法來改變組件的某(些)狀態,也能夠經過 props 的值的變化來改變組件自身的同一個(些)狀態。javascript

組件改變本身的狀態只能經過改變 state 完成,而把 props 的變化反映到 state 倒是能夠經過生命週期函數來實現。首先仍是拿上一篇中受控 alert 組件代碼爲例:java

class Alert extends React.Component {
  constructor( props ) {
    super( props )
    this.state = {
      content: '',
      show: false
    }
    this.show = ( content )=>{
      this.setState( {
        content: content,
        show: true
      } )
    }

    this.hide = ()=>{
      this.setState( {
        show: false
      } )
    }
  }
  render() {
    let style = {
      display: this.state.show ? 'fixed' : 'none'
    }
    return (
      <div class="my-alert" style={ style } >
        <div class="my-alert-tit">Alert</div>
        <div>{ this.state.content }</div>
        <div class="my-alert-footer">
          <button onClick={ this.hide }>肯定</button>
        </div>
      </div>
    );
  }
}

組件初始化的時候構造函數會接受傳入的 props ,而當組件的容器改變傳入組件的 props 的值時會觸發組件的 componentWillReceiveProps 的方法,在這個方法中咱們能夠把變化後的 props(nextProps) 經過 setState 映射成 state 的變化。那麼咱們須要作的就是給受控組件增長初始化 props 處理和在 componentWillReceiveProps 內 props 的處理。ajax

class Alert extends React.Component {
  constructor( props ) {
    super( props )
    this.state = {
      content: this.props.content || '',
      show: this.props.show || false
    }
    this.show = ( content )=>{
      this.setState( {
        content: content,
        show: true
      } )
    }

    this.hide = ()=>{
      this.setState( {
        show: false
      } )
    }
  }

  componentWillReceiveProps( nextProps ) {
    this.setState( nextProps );
  }

  render() {
    let style = {
      display: this.state.show ? 'fixed' : 'none'
    }
    return (
      <div class="my-alert" style={ style } >
        <div class="my-alert-tit">Alert</div>
        <div>{ this.state.content }</div>
        <div class="my-alert-footer">
          <button onClick={ this.hide }>肯定</button>
        </div>
      </div>
    );
  }
}

那麼針對同一個 alert 組件的使用就變得多樣化,能夠根據本身項目的需求來變化。譬如:編程

import { Alert } from 'Alert';

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      alertMsg: '',
      showAlert: false
    }
    this.saveHandler = ()=>{
      // save ajax success
      this.refs.myAlert.show( 'Save successfully' );
    }
    this.removeHandler = ()=>{
      // remove ajax success
      this.setState( {
        alertMsg: 'Remove successfully',
        showAlert: true
      } )
    }
  }

  render() {
    <div>
      <button onClick={ this.saveHandler }>Save</button>
      <button onClick={ this.removeHandler }>Remove</button>
      <Alert ref="myAlert" content={ this.state.alertMsg } show={ this.state.showAlert }/>
    </div>
  }
}

爲了讓組件更健壯,咱們對 state 和 props 的一些必須的初始化值(默認值)須要明確指定redux

class Alert extends React.Component {
  constructor( props ) {
    super( props )
    let content = this.props.content;
    let show = this.props.show;
    /*
      props.xxx 的優先級比 props.defautXxx 高,
      若是設置了props.xxx 則 props.defaultXxx 就不起做用
    */
    this.state = {
      content: content === undefined ? this.props.defaultContent : content
      show: show === undefined ? this.props.defaultShow : show
    }
  }
}
Alert.propTypes = {
  defaultShow: React.PropTypes.bool,
  defaultContent: React.PropTypes.string,
  show: React.PropTypes.bool,
  content: React.PropTypes.string
}

Alert.defaultProps = {
  defaultShow: false,
  defaultContent: ''
}

如上代碼若是對 props.xxx 和 props.defaultXxx 有迷惑的童鞋,其實有了 xxx 徹底沒有必要再有 defaultXxx,可是參考一些組件庫的 api 設計,我理解爲是爲了保持受控組件 api 的統一性,若是把 alert 組件當成受控組件則初始化使用 defaultXxx,若是當成非受控組件就直接使用 xxx。api

那何時使用受控組件,何時使用非受控組件呢?咱們知道受控組件是比較符合咱們傳統 UI 組件開發的思路的。可是 React 在跨組件通信方面很弱,若是不借助第三方庫進行通信,對於兩個毫無關係的組件相互調用就須要傳遞層層的回調函數。我想沒有人喜歡這種編程風格,因此把全部組件的狀態抽象到一個地方進行集中管理變化,典型的數據流用 redux 就傾向於使用非受控組件了(這裏不討論flux思想的由來,不討論redux好壞)。ide

故最基本的 React 組件編寫套路就這些。可是這些還只是 api 應用層面的東西,比較難的是在編寫組件時候對狀態的抽象,使使用者使用的舒服天然。函數

相關文章
相關標籤/搜索