上一篇講了 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 應用層面的東西,比較難的是在編寫組件時候對狀態的抽象,使使用者使用的舒服天然。函數