上一篇讲了 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 应用层面的东西,比较难的是在编写组件时候对状态的抽象,使使用者使用的舒服天然。函数