React系列之(二)-React组件的生命周期

在组件的整个生命周期中,随着该组件的props或者state的变化,它的DOM表现也将有相应的改变,一个组件就是一个状态机,对于特定的输入,它总会返回一致的输出。

React为每个组件提供了勾子函数去响应不同的时期–创建时,存在时以及销毁时。

创建时

当你首次使用一个组件类时,你会看到下面的这些方法依次被调用:

  1. getDefaultPops
  2. getInitialState
  3. componentWillMount
  4. render
  5. componentDidMount

getDefaultPops

对于组件类来说,这个方法只会被调用一次,该组件类的所有后续应用,getDefaultPops将不会再被调用,它用于返回组件实例的默认props值,值得注意的是,任何引用类型的值(如数组,对象),都会在所有实中共享,而不是每个组件实例拥有单独的副本,所以不要在组件实例中去修改props,把它当成只读的数据最好。

getInitialState

对于每个组件实例来讲,这个方法只会调用一次,注意它和getDefaultPops的调用是有区别的,getDefaultPops是对于组件类来说只调用一次,后续该类的应用都不会被调用,而getInitialState是对于每个组件实例来讲都会调用,并且只调一次。它用来初始化每个实例的state,在这个方法里,可以访问组件的props.值得注意的是,在getInitialState方法中,尝试通过this.props来创建state的做法是一种反模式。React专注于维护数据的单一来源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//反模式
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值不同步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//正确写法
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是没有问题的。
比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//简单的初始化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节点,并操作它。

存在时

此时组件已经渲染好并且用户可以与它进行交互,比如鼠标点击,手指点按,或者其它的一些事件,导致应用状态的改变,你将会看到下面的方法依次被调用

  1. componentWillReceiveProps
  2. shouldComponentUpdate
  3. componentWillUpdate
  4. render
  5. componentDidUpdate

componentWillReceiveProps

组件的props属性可以通过父组件来更改,这时,componentWillReceiveProps将来被调用。可以在这个方法里更新state,以触发render方法重新渲染组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//实现一个简单的全选与全不选效果
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这个组件还需要作一些小调整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//一个简单的计时器
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让我们可以去处理,实现我们想要的效果。

关于猫头鹰团队

武汉很少有优秀的互联网公司,但是:

  • 有很多湖北籍/华中籍的在一线城市/一线互联网公司打拼的优秀人才,他们因为家庭,房价等各种原因,期望回到武汉。
  • 不少优秀人才回到武汉后,因为没有互联网土壤,因为理念的不一致,处境很尴尬,甚至很多人生活所迫又重新回到一线城市。
  • 另外一种情况是,很多武汉的本地公司,他们又希望能够拥抱互联网,又找不到真正懂互联网的优秀人才。

我们希望通过各种方式,团聚湖北籍/华中籍的优秀互联网人才,首先打造一家真正的互联网公司,最终改变整个武汉互联网的从业环境, 更多细节请“查看原文”后点击这里

长按关注猫头鹰技术公众号(mtydev)

img

留言

本站总访问量

留言