简单地说,React Component通过其定义的几个函数来控制组件在生命周期的各个阶段的动作 官方文档
组件的生命周期可分成三个状态:
- Mounting:已插入真实 DOM
- Updating:正在被重新渲染
- Unmounting:已移出真实 DOM
生命周期的方法有:
- componentWillMount 在渲染前调用,在客户端也在服务端。
- componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异部操作阻塞UI)。
- componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
- shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。 - componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
- componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
- componentWillUnmount在组件从 DOM 中移除的时候立刻被调用。
为了方便大家理解 ,我们可以从图和代码两方面理解
- 首先我们先看新载入一个组件时
class LifeCycle extends React.Component {
static defaultProps={ //这就是图中左侧的静态默认属性
name :'zzz'
}
constructor(props){
super()
console.log('constructor');
}
componentWillMount(){
console.log('componentWillMount');
}
componentDidMount(){
console.log('componentDidMount');
}
render(){
console.log('render');
return(
<div>
{this.props.name}
</div>
)
}
}
当我们新载入一个组件时,不做任何操作,此时加载的先后顺序我们可以在控制台输出出来
此时进行的是图里面的左侧的部分,这个代码只在最开始时执行一次。
class LifeCycle extends React.Component {
static defaultProps={
name :'zzz'
}
constructor(props){
super()
console.log('constructor');
this.state = {name:props.name,count:1}
}
componentWillMount(){
console.log('componentWillMount');
}
componentDidMount(){
console.log('componentDidMount');
}
render(){
console.log('render');
return(
<div>
计数器:{this.state.count}
<button onClick={()=>{this.setState({count:this.state.count+1})}}>+</button>
</div>
)
}
}
这里增加了一个计数器,当点击+的时候让count加1,看控制台可以看出 ,后面执行代码只走render了
即使这count不更改,也会重新渲染
2.shouldComponentUpdate
shouldComponentUpdate如果这个函数不写在组件里的话默认相当于返回一个true,但是,这里我们可以做一个优化,如果上一个值和执行后的结果相等的话就不走代码了
class LifeCycle extends React.Component {
static defaultProps={
name :'zzz'
}
constructor(props){
super()
console.log('constructor');
this.state = {name:props.name,count:1}
}
componentWillMount(){
console.log('componentWillMount');
}
componentDidMount(){
console.log('componentDidMount');
}
render(){
console.log('render');
return(
<div>
计数器:{this.state.count}
<button onClick={()=>{this.setState({count:1})}}>+</button>
</div>
)
}
shouldComponentUpdate(nextProps,nextState){//如果没有使用这个生命周期的话,默认相当于返回true
//优化一下,如果上一个值和现在的值一样就不重新渲染
if(nextState.count === this.state.count){
return false
}
return true
}
}
执行之后发现点击按钮没有任何状态更新。
3. componentWillUpdate&componentDidUpdate
组件更新变化
class LifeCycle extends React.Component {
static defaultProps={
name :'zzz'
}
constructor(props){
super()
console.log('constructor');
this.state = {name:props.name,count:1}
}
componentWillMount(){
console.log('componentWillMount');
}
componentDidMount(){
console.log('componentDidMount');
}
render(){
console.log('render');
return(
<div>
计数器:{this.state.count}
<button onClick={()=>{this.setState({count:this.state.count+1})}}>+</button>
</div>
)
}
shouldComponentUpdate(nextProps,nextState){//如果没有使用这个生命周期的话,默认相当于返回true
console.log('shouldComponentUpdate');
//优化一下,如果上一个值和现在的值一样就不重新渲染
if(nextState.count === this.state.count){
return false
}
return true
}
componentWillUpdate(){ //这个已经放弃了,16.3之后又出来一个新的方法替代它
console.log('componentWillUpdate');
}
componentDidUpdate(){
console.log('componentDidUpdate');
}
}
点击按钮可以看到控制台输出
4. 如果有子组件和父组件混合会怎么走呢
<div>
计数器:{this.state.count}
<button onClick={()=>{this.setState({count:this.state.count+1})}}>+</button>
<Child></Child>
</div>
class Child extends React.Component {
constructor(props){
super()
console.log('Child:constructor');
}
componentWillMount(){
console.log('Child:componentWillMount');
}
componentDidMount(){
console.log('Child:componentDidMount');
}
render(){
console.log('Child:render');
return(
<div>
子组件
</div>
)
}
}
执行结果是
如果这个时候点击+号,子组件也会渲染
当父组件把count传给了子组件,这个时候就走了componentWillReceiveProps,如图所示,只有在运行并传给新值的时候才会走这个方法。
只有可以调setState方法可以更新。
这里补充一个新的方法 getDerivedStateFromProps
这是一个静态方法,从属性中获取状态,这个要求组件必须有状态,也必须有返回值,并且如果返回的是个对象,则这个对象会变成这个组件的状态。这个方法中没有this
class Child extends React.Component {
constructor(props){
super()
this.state={}
console.log('Child:constructor');
}
// componentWillMount(){
// console.log('Child:componentWillMount');
// }
componentDidMount(){
console.log('Child:componentDidMount');
}
static getDerivedStateFromProps(){
console.log('Child:getDerivedStateFromProps');
return {a:1000}
}
render(){
console.log('Child:render');
return(
<div>
{this.props.count}
子组件
{this.state.a}
</div>
)
}
// componentWillReceiveProps(){
// console.log('Child:componentWillReceiveProps');
// }
}
执行结果如下
还有一个鸡肋的方法 getSnapshotBeforeUpdate
,得到更新前的快照。官方都不建议用。