上一篇讲了 React 两种最常见的组件:受控组件和非受控组件。为了可用性,我们平常编写出来的组件愿望支撑这两种特征:能够经由过程组件本身的要领来转变组件的某(些)状况,也能够经由过程 props 的值的变化来转变组件本身的同一个(些)状况。
组件转变本身的状况只能经由过程转变 state 完成,而把 props 的变化反应到 state 倒是能够经由过程生命周期函数来完成。起首照样拿上一篇中受控 alert 组件代码为例:
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 的处置惩罚。
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 的一些必需的初始化值(默认值)须要明白指定
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。
那什么时刻运用受控组件,什么时刻运用非受控组件呢?我们晓得受控组件是比较相符我们传统 UI 组件开辟的思绪的。然则 React 在跨组件通信方面很弱,假如不借助第三方库举行通信,关于两个毫无关系的组件互相挪用就须要通报层层的回调函数。我想没有人喜好这类编程作风,所以把一切组件的状况笼统到一个处所举行集合治理变化,典范的数据流用 redux 就倾向于运用非受控组件了(这里不议论flux头脑的由来,不议论redux优劣)。
故最基本的 React 组件编写套路就这些。然则这些还只是 api 应用层面的东西,比较难的是在编写组件时刻对状况的笼统,使运用者运用的惬意天然。