在组件的整个生命周期中,随着该组件的props或者state的变化,它的DOM表现也将有相应的改变,一个组件就是一个状态机,对于特定的输入,它总会返回一致的输出。
React为每个组件提供了勾子函数去响应不同的时期——创建时,存在时以及销毁时。
创建时
当你首次使用一个组件类时,你会看到下面的这些方法依次被调用:
- getDefaultPops
- getInitialState
- componentWillMount
- render
- componentDidMount
getDefaultPops
对于组件类来说,这个方法只会被调用一次
,该组件类的所有后续应用,getDefaultPops将不会再被调用,它用于返回组件实例的默认props值,值得注意的是,任何引用类型的值(如数组,对象),都会在所有实实例中共享,而不是每个组件实例拥有单独的副本,所以不要在组件实例中去修改props,把它当成只读的数据最好。
getInitialState
对于每个组件实例来讲,这个方法只会调用一次
,注意它和getDefaultPops的调用是有区别的,getDefaultPops是对于组件类来说只调用一次,后续该类的应用都不会被调用,而getInitialState是对于每个组件实例来讲都会调用,并且只调一次。它用来初始化每个实例的state,在这个方法里,可以访问组件的props.值得注意的是,在getInitialState方法中,尝试通过this.props来创建state的做法是一种反模式。React专注于维护数据的单一来源。
//反模式
var
CountDown = React.createClass({ getDefaultPops :
function
(){
return
{ date :
new
Date
() } },
getInitialState :
function
(){
retrun
{ surplus :
this
.props.date -
new
Date
() } },
render :
function
(){
return
(
<div>
{this.state.surplus}
</div>
) }})
上面这种就是一种反模式,经过计算后的值不应该赋给state,正确的模式应该是在渲染时计算这些值。这样保证了计算后的值永远不会与派生出它的props值不同步。
//正确写法
var
CountDown = React.createClass({ getDefaultPops :
function
(){
return
{ date :
new
Date
() } },
render :
function
(){
var
surplus =
this
.props.date -
new
Date
();
return
(
<div>
{surplus}
</div>
) }})
然而,如果你的目的并不是同步,而是简单的初始化state,那么在getInitialState方法中使用props是没有问题的。
比如:
//简单的初始化state
var
Checkbox = React.createClass({ getDefaultPops:
function
(){
return
{ checked : false } }, getInitialState :
function
(){
return
{ checked :
this
.props.checked } }, render:
function
(){
return
(
<div
className
=
"checkbox"
>
<input
type
=
"checkbox"
checked
=
{this.state.checked}
/>
</div>
) }})
componentWillMount
此方法在初始化之后,渲染之前被调用。
render
render方法会创建一个虚拟DOM,用来表示组件的输出。对于一个组件来讲,render方法是唯一一个必需的方法。render方法需要满足下面几点:
- 只能通过 this.props 和 this.state 访问数据
- 可以返回null,false或者任何React组件
- 只能出现一个顶级组件,不能返回一组元素(新手特别注意)
render方法返回的结果并不是真正的DOM元素,而是一个虚拟的表现,类似于一个DOM tree的结构的对象。react之所以效率高,就是这个原因。
componentDidMount
在render方法成功执行并真实的DOM已经被渲染后,componentDidMount方法才会被执行,你可以在该方法内部获取DOM节点,并操作它。
存在时
此时组件已经渲染好并且用户可以与它进行交互,比如鼠标点击,手指点按,或者其它的一些事件,导致应用状态的改变,你将会看到下面的方法依次被调用
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
componentWillReceiveProps
组件的props属性可以通过父组件来更改,这时,componentWillReceiveProps将来被调用。可以在这个方法里更新state,以触发render方法重新渲染组件。
//实现一个简单的全选与全不选效果
var
Checkbox = React.createClass({ getDefaultPops:
function
(){
return
{ checked : false } },
getInitialState :
function
(){
return
{ checked :
this
.props.checked } },
componentWillReceiveProps :
function
(nextProps){
if
(nextProps.checked !==
this
.state.checked){
this
.setState({ checked:nextProps.checked }); } },
render :
function
(){ <div className=
"checkbox"
>
<input
type
=
"checkbox"
checked
=
{this.state.checked}
/>
</div>
}});
var AllChoose = React.createClass({ getDefaultPops : function(){ return { checked : false } },
getInitialState : function(){ return { checked : this.props.checked } },
handleChange : function(){ this.setState({ checked : !this.state.checked }); },
render : function(){ return (
<div
className
=
"checkbox"
>
<input
type
=
"checkbox"
checked
=
{this.state.checked}
onChange
=
{this.handleChange}
/>
<Checkbox
checked
=
{this.state.checked}
/>
<Checkbox
checked
=
{this.state.checked}
/>
<Checkbox
checked
=
{this.state.checked}
/>
</div>
); }});
shouldComponentUpdate
如果你确定组件的props或者state的改变不需要重新渲染,可以通过在这个方法里通过返回false来阻止组件的重新渲染,返回false则不会执行render以及后面的componentWillUpdate,componentDidUpdate方法。继续上面的例子,比如上面的第二个checkbox因为某些原因为禁用了,那么即使全选这个checkbox被选中了,它也不应该跟着一起被选中,所以Checkbox这个组件还需要作一些小调整
var
Checkbox = React.createClass({ getDefaultPops:
function
(){
return
{ checked : false, disabled : false } },
getInitialState :
function
(){
return
{ checked :
this
.props.checked, disabled :
this
.props.disabled } },
componentWillReceiveProps :
function
(nextProps){
if
(nextProps.checked !==
this
.state.checked) {
this
.setState({ checked : nextProps.checked }); } },
shouldComponentUpdate :
function
(){
return
!
this
.state.disabled
//当checkbox的disabled属性为true时,取反,返回false,阻止重新渲染
},
render :
function
(){ <div className=
"checkbox"
>
<input
type
=
"checkbox"
checked
=
{this.state.checked}
/>
</div>
}});
componentWillUpdate
这个方法和componentWillMount类似,在组件接收到了新的props或者state即将进行重新渲染前,该方法会被调用,注意不要在此方面里再去更新props或者state.
componentDidUpdate
这个方法和componentDidMount类似,在组件重新被渲染之后,它会被调用。可以在这里访问并修改DOM。
销毁时
随着一个组件从它的层级结构中被移除,这个组件的生命也算是走到了尽头,此时componentWillUnmout会被执行,提供一个让你做一些清理工作的机会。
componentWillUnmout
比如现在有一个组件,里面有一个循环执行的函数,当这个组件被销毁时,我们需要停止这个循环,否则会造成资源上的浪费,这个停止的语句就可以写在componentWillUnmout里。
//一个简单的计时器
var
Clock = React.createClass({ getInitialState :
function
(){
return
{ now :
new
Date
()-
0
} }, tick :
function
(){
this
.setState({now:
new
Date
()-
0
}) }, componentDidMount :
function
(){
this
.interval = setInterval(
this
.tick,
1000
); }, componentWillUnmout :
function
(){ clearInterval(
this
.interval);
//清除setInterval,释放资源
}, render :
function
(){
return
(
<div>
{this.state.now}
</div>
) }})
以上就是react组件在不同时间所提供的API,在每一个时间节点上都有相应的API让我们可以去处理,实现我们想要的效果。