React組件編寫思路(一)

新手寫 React 組件每每無從入手,怎麼寫,何時用 props,何時用 state 摸不着頭腦。實際上是沒有了解到 React 的一些思想。就我我的的經驗大多數的組件都有必定的套路可言,接下來就先介紹下 React 組件的基本思想。javascript

React 組件能夠分爲可控組件和非可控組件。可控組件意思是組件自身控制本身的狀態(屬性),能夠經過自身提供的方法(供調用者使用)來改變本身的狀態。譬如一個 input text 輸入框提供一個 reset 方法,若是要清空用戶輸入則經過得到 inupt 組件對象,而後調用 reset 方法來作java

refs.inputRef.rest() 。

非可控組件的意思是組件自己的狀態(屬性)本身沒法更改,只能隨着外部傳入的值(props)而變化。仍是拿輸入框清空這一個操做來講,非可控的 input 不經過本身提供方法來改變(維護)本身的狀態(value),只經過外部傳入一個值爲空字符串的 value 來作到清空的效果。ajax

reset(){
  this.setState({
    inputValue: ''
  })
}
render(){
  return <input value={this.state.inputValue}/>
}

咱們拿一個場景來看下完整的代碼(一個 form 中有一個 input,有一個 reset 按妞,點擊 reset 按妞會清空用戶的輸入),看下這兩種組件書寫的區別。
受控組件例:ide

class App extends React.Component {
  reset = ()=>{
    this.refs.myInput.reset() // 假設 input 有一個 reset 方法
  }
  render() {
    <div>
      <form>
        <input type="text"  ref="myInput" />
        <button onClick={ this.reset }>Reset</button>
      </form>
    </div>
  }
}

非受控組件例:this

class App extends React.Component {
  constructor( props ){
    super( props );
    this.state = {
      inputValue: 'Plz input your text.'
    }
  }
  reset = ()=>{
    this.setState( {
      inputValue: ''
    } )
  }
  render() {
    <div>
      <form ref="myForm">
        <input type="text" value={ this.state.inputValue }/>
        <button onClick={ this.reset }>Reset</button>
      </form>
    </div>
  }
}

接下來咱們來看下若是編寫這兩種組件,打個比方咱們要自定義一個 alert 組件。咱們先從非受控組件提及,由於較簡單。非受控組件所要作的就是把全部狀態提取到組件的 props 中去,render 中就用 props。一個 alert 有哪些最基本的狀態(屬性)呢?咱們以最基礎的功能定出一個表示顯示與否的 show,一個表示顯示內容的 content。那麼組件代碼以下。rest

class Alert extends React.Component {
  constructor( props ) {
    super( props )
  }
  render() {
    let style = {
      display: this.props.show ? 'fixed' : 'none'
    }
    return (
      <div class="my-alert" style={ style } >
        <div class="my-alert-tit">Alert</div>
        <div>{ this.props.content }</div>
        <div class="my-alert-footer">
          <button>肯定</button>
        </div>
      </div>
    );
  }
}

Alert.propTypes = {
  show: React.PropTypes.bool,
  content: React.PropTypes.string
}

咱們看到最直觀的就是隻須要考慮到 props 的可能取值就行,不須要關心如何改變props。而使用這個非可控 alert 的代碼以下:code

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

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

接下來咱們看下可控組件的alert怎麼寫。可控組件經過方法來供調用者來改變組件的狀態(屬性)。因此暫時咱們不定義 props 只定義幾個方法 show(content), hide()。組件代碼以下:orm

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>
    );
  }
}

咱們看到可控組件內部須要用到 state 來本身改變本身的狀態。使用這個可控 alert 的代碼以下:對象

import { Alert } from 'Alert';

class App extends React.Component {
  constructor() {
    super();
    this.saveHandler = ()=>{
      // ajax success
      this.refs.myAlert.show( 'Save Successfully' );
    }
  }

  render() {
    <div>
      <button onClick={ this.saveHandler }>Save</button>
      <Alert ref="myAlert"/>
    </div>
  }
}

可是可控組件有一個問題就是他的初始化狀態如何設置(如何由外部定義組件 state 的初始化值)?因爲沒有 props 那麼只能經過方法來設置,那麼這麼作法很彆扭。這時能夠經過定義 props 把初始化狀態在生成這個組件時傳入,而沒必要等組件生成完再經過調用方法傳入。因而修改後的代碼以下:ip

class Alert extends React.Component {
  constructor( props ) {
    super( props )
    this.state = {
      content: this.props.defaultContent,
      show: this.props.defaultShow
    }
    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>
    );
  }
}

Alert.propTypes = {
  defaultShow: React.PropTypes.bool,
  defaultContent: React.PropTypes.string
}

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

使用這個組件的代碼:

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      alertMsg: '',
      showAlert: false
    }
    this.saveHandler = ()=>{
      // ajax success
      this.refs.myAlert.show( 'Save Successfully' );
    }
  }

  render() {
    <div>
      <button onClick={ this.saveHandler }>Save</button>
      <Alert ref="myAlert" defaultShow={false} defaultContent={''}/>
    </div>
  }
}

以上就是兩種 React 組件的編寫思路,你能夠選擇把你的組件編寫成任意一種,那麼使用者使用時也會有所不一樣。可是做爲一個具備良好可用性的組件,不該該限制使用者的用法,那麼下篇將介紹如何編寫一個既能夠做爲可控組件,也能夠做爲一個非可控組件的組件寫法。

相關文章
相關標籤/搜索