应对生命周期的是组件的生命周期函数,在组件从创建,加载,到最后删除的这段周期里,不同的时间点,React 框架都会调用组件的不同的生命周期函数。这些函数被调用时,本质上是框架在传达信息,它告诉我们,组件当前正在处于某个特殊的时间点上。
生命周期函数就是组件本身具备的一些被框架在适当时间调用的固定接口而已,先看几个比较重要的几个周期函数:
1,componentWillMount
2,componentDidMount
3,componentWillUnmount
4,componentWillUpdate
5,componentDidUpdate
6, shouldComponentUpdate
7,componentWillRecieveProps
通过构建实例来看看这些函数是怎么发挥作用的
例:
var CounterParent = React.createClass({
getDefaultProps: function() {
console.log("getDefaultProps:receive props from outsize");
return {};
},
getInitialState:function() {
console.log("getInitialiState:set default state object");
return {};
},
componentWillMount: function() {
console.log("componentWillMount:component is about to mount");
return;
},
componentDidMount: function() {
console.log("componentDidMount:component is just mount");
},
render: function() {
var s = "CounterParent rendering...."
return (
<div>
{s}
</div>
)
}
})
ReactDOM.render(
<div>
<CounterParent/>
</div>,
destination
);
几个函数的调用次序如下:
1, 先被调用的是getDefaultProps 函数,在这个函数初始化this.props 对象
2,接着被调用的是getInitialState接口,这个接口用于初始化组件的state对象。
3, 接着被调用的是componentWillMount, 这是组件绘制前最后一个个被调用的接口,这个接口被调用之后,React框架就会调用组件的render函数,把组件绘制到界面上,
注意:在这例如果调用setState接口来改变组件的state对象的话,那么render 接口将不会被框架调用。
继续添加代码,以便后续分析,新代码更新如下:
接着也给CounterParent也妆点一下:
var CounterParent = React.createClass({
....
render: function() {
var backgroundStyle = {
padding: 50,
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
};
return (
<div style={backgroundStyle}>
<button> + </button>
</div>
)
});
给组件添加了一个加号按钮,还没有深入研究组件如何响应用户输入,
再创建一个子组件,用来显示一个计数信息,当点击加号按钮时,可以让计数加一,代码如下:
var Counter = React.createClass({
render: function() {
var textStyle = {
fontSize: 72,
fontFamily: "sans-serif",
color: "#333",
fontWeight: "bold"
};
return (
<div style={textStyle}>
{this.props.display}
</div>
)
}
});
它将作为CounterParent的一个子组件,所以在CounterParent的render函数里要调用它:
var CounterParent = React.createClass({
...
render: function() {
var backgroundStyle = {
padding: 50,
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
}
}
return (
<div style={backgroundStyle}>
<Counter display="0"/>
<button> + </button>
</div>
)
});
完成上面代码后,加载到浏览器后,发现在加号按钮的上面多了一大大的数字0.但现在点击按钮时,上面数字没有反应 。要想让组件根据应用场景变化的话,就得需要组件的状态对象机制,因此给CounterParent组件添加相关的状态信息。代码如下:
var CounterParent = React.createClass({
...
getInitialState: function() {
console.log("getInitialiState: set default state object");
return {
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
};
}
....
render: function() {
var backgroundStyle = {
padding: 50,
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count}/>
<button> + </button>
</div>
)
}
....
});
点击加号按钮时,数值能自动增加,因此需要添加加号按钮点击后的响应函数,代码如下:
var CounterParent = React.createClass({
...
increase: function() {
this.setState({
count: this.state.count + 1
});
},
....
render: function() {
var backgroundStyle = {
padding: 50,
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count}/>
<button onClick="this.increase"> + </button>
</div>
)
}
....
});
state 更新流程:
把计数变量存储在state对象的count变 中,每次按钮点击时 ,它的onClick事件被出发,然后调用increase函数,在该函数里它通过setState改变state对象中count变 的值,state对象改变后,react 框架自动调用组件的render函数,于是新的计数值便绘制到界面上。
接下来组件的状态对象改变后所引发的一系列周期函数调用。当点击加号按钮后,increase函数被调用,它再调用setState函数改变组件的state对象,进而引发React框架对组件接口的一系列调用。state对象改变后组件的shouldComponentUpdate 接口先被调用。
shouldComponentUpdate的逻辑:
var CounterParent = React.createClass({
shouldComponentUpdate: function(newProps, newState) {
console.log("shouldComponentUpdate: Should component update?");
if (newState.count < 5) {
console.log("Component should update");
return true;
} else {
console.log("Component should not update!");
return false;
}
},
});
该函数被框架调用后,如果返回true那么React框架将继续执行组件更新的相关流程,直到最后调用render函数,如果返回false,那么React框架将终止更新流程,不会调用render函数。
框架调用该接口时,传入两个参数,分别是newProps,这个参数对应的是组件的属性对象,也就是props对象,第二个参数是更新后的state对象,在代码中,判断state对象里面的count变量它的值是否比5大,如果大过5,那么返回false,这样当持续点击按钮,计数数字会持续增加,但一旦增加到5的时候,再点击按钮界面上的数值就不会增加了。
如果返回true的话,React框架将调用组件的componentWillUpdate 接 ,把代码添加上:
componentWillUpdate: function(newProps, newState) {
console.log("componentWillUpdate: Component is about to update");
},
这个函数调用后,框架就会调用render函数更新界面了,最后调用的接口是componentDidUpdate,代码如下:
componentDidUpdate: function(currentProps, currentState) {
console.log("componentDidUpdate: component just updated");
return;
},
完成代码后,在每个函数里面添加断点,然后点击一下加号按钮可以看到,首先componentShouldUpdate, componentWillUpdate 先后被调 ,然后render被调 ,于是界面上的计数信息更改,接着componentDidUpdate继续被调用。尝试继续点击按钮,让计数增加超过5后看看效果。
组件的消亡流程
当组件被删除时,在它被销毁前,它的接口componentWillUnmount 将会被调用,添加相关代码如下:
componentWillUnmount: function() {
console.log("componentWillUnmount: component is removing from DOM");
return;
},
为了触发组件的销毁事件,在计数增长到5时,调用ReactAPI:ReactDOM.unmountComponentAtNode 将加载的组件从DOM中删除掉,这样unmout事件就能被触发了,代码修改如下:
shouldComponentUpdate: function(newProps, newState) {
console.log("shouldComponentUpdate: Should component update?");
if (newState.count < 5) {
console.log("Component should update");
return true
} else { console.log(" Component should not update!");
ReactDOM.unmountComponentAtNode(destination);
return false;
}
},
分别在else 和componentWillUnmount函数中设置断点,然后点击按钮,让数值增加到5,可以发现一旦unmountComponentAtNode调用之后,componentWillUnmount 接着被调用,最后组件被框架从DOM中拿掉,于是 上面显示的信息也消失了
结论:
可以看到,常使用的组件,看似平淡无奇,但当深入解剖它的运行机制时,会发现另外一个隐藏着的难以察觉的运行机制,React框架一直在监视着组件的状态,并在合适的时机通过调用周期函数的方式通知我们,了解和掌握好react组件的命周期机制,对今后开发更复杂的网页运用会打下坚实的基础。