您当前的位置: 首页 > 慢生活 > 程序人生 网站首页程序人生
9.组件生命周期
发布时间:2025-02-24 23:05:56编辑:雪饮阅读()
-
关于react的生命周期,且看如下示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
/*
* 在 React 中,getInitialState是React早期版本中的,该方法已经被废弃(网上有说16.3时被废弃的,但我的是16.1.0的development版本,具体情况我觉得这里貌似没有纠结的必要了。),
* 并被新的生命周期方法 constructor 替代
*
* */
getInitialState(){
console.log("getInitialState");
return {
count:1
}
}
constructor(props){
console.log("constructor是代替getInitialState的函数");
super(props);
this.state = {
count: 0,
};
}
/*
getDefaultProps(){
console.log("getDefaultProps");
return {}
}
getDefaultProps周期函数 这是React早期版本中的一个功能(是React.createClass函数接收的对象中这样定义的) 这种方式已经被弃用。
网上有说16.3时被废弃的,但我的是16.1.0的development版本,具体情况我觉得这里貌似没有纠结的必要了。
如果非用这样的方式,就会在浏览器中被抛出控制台中如果警告
Warning: getDefaultProps is only used on classic React.createClass definitions. Use a static property named `defaultProps` instead.
*/
//static defaultProps这种方式是取代getDefaultProps的
static defaultProps = {
message: '默认消息'
}
componentWillMount(){
//组件即将被挂载的生命周期函数
console.log('componentWillMount');
}
componentDidMount(){
//组件已经被挂载的生命周期函数
console.log("componentDidMount");
}
render(){
return (
<div>
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h3>我是子组件</h3>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
将该示例运行,然后查看控制台的输出,你大概也就都懂了吧。
render其实也算是生命周期函数了,在渲染时候调用的。
而componentWillMount生命周期函数里面对响应数据的操作并不会造成二次渲染,如下示例只会在控制台输出一次“渲染”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
/*
虽然constructor会替代已废弃的getInitialState,但是你定义getInitialState,并不会报错,但也没有意义了
getInitialState(){
console.log("getInitialState");
return {
count:1
}
}
*/
constructor(props){
console.log("constructor是代替getInitialState的函数");
super(props);
this.state = {
count: 0,
};
}
static defaultProps = {
message: '默认消息'
}
componentWillMount(){
//组件即将被挂载的生命周期函数
console.log('componentWillMount');
this.setState({
count:2
})
}
componentDidMount(){
//组件已经被挂载的生命周期函数
console.log("componentDidMount");
}
render(){
console.log('渲染');
return (
<div>
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h3>我是子组件</h3>
<div>count:{this.props.count}</div>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
渲染之后就可以获取到dom节点,在渲染之后就比较适合发送ajax请求之类的了。
如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
constructor(props){
console.log("constructor是代替getInitialState的函数");
super(props);
this.state = {
count: 0,
};
//this.myRef = React.createRef();
}
static defaultProps = {
message: '默认消息'
}
componentWillMount(){
//组件即将被挂载的生命周期函数
console.log('componentWillMount');
this.setState({
count:2
})
}
componentDidMount(){
//组件已经被挂载的生命周期函数
console.log("componentDidMount");
/*
在老版本中componentDidMount生命周期函数里面就可以直接拿到dom节点,用this.getDOMNode()即可拿到
但新版中componentDidMount生命周期函数里面鼓励使用this.refs去调用对于dom节点
*/
// console.log(this.getDOMNode());
console.log(this.refs['goodInput']);
}
render(){
console.log('渲染');
return (
<div>
<div ref="goodInput">Hello, world!</div>;
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h3>我是子组件</h3>
<div>count:{this.props.count}</div>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
componentWillUnmount生命周期函数在组件被卸载的时候触发。我们来模拟删除组件自己来试试。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
constructor(props){
console.log("constructor是代替getInitialState的函数");
super(props);
this.state = {
count: 0,
};
}
static defaultProps = {
message: '默认消息'
}
componentWillMount(){
console.log('componentWillMount');
this.setState({
count:2
})
}
componentDidMount(){
console.log(this.refs['goodInput']);
}
componentWillUnmount(){
var info='you are tring to kill me !!';
console.log(info);
alert(info);
}
killMySelf(){
/*
在旧版本中可以使用 React.unmountComponentAtNode来卸载组件自身,传递组件自身绑定的元素即可
React.unmountComponentAtNode(document.getElementById('app'));
但新版中已废弃,改为使用ReactDOM来调用,也不算是废弃,只是换了一个调用的对象,方法名还是相同,传的这第一个参数也是相同的
*/
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
}
render(){
console.log('渲染');
return (
<div>
<div ref="goodInput">Hello, world!</div>;
<button onClick={this.killMySelf}>卸载掉这个组件</button>
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h3>我是子组件</h3>
<div>count:{this.props.count}</div>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
那么我们现在做一个实验,在即将挂载的生命周期上写一个timer,每1秒自增下count,然后我们在点击按钮来卸载当前组件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
constructor(props){
console.log("constructor是代替getInitialState的函数");
super(props);
this.state = {
count: 0,
};
}
static defaultProps = {
message: '默认消息'
}
componentWillMount(){
console.log('componentWillMount');
var self=this;
this.timer=setInterval(function(){
self.setState({
count:self.state.count+1
})
},1000)
}
componentDidMount(){
console.log(this.refs['goodInput']);
}
componentWillUnmount(){
var info='you are tring to kill me !!';
console.log(info);
alert(info);
}
killMySelf(){
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
}
render(){
console.log('渲染');
return (
<div>
<div ref="goodInput">Hello, world!</div>;
<button onClick={this.killMySelf}>卸载掉这个组件</button>
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h3>我是子组件</h3>
<div>count:{this.props.count}</div>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
可以看到控制台中有如下报错:
Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.
Please check the code for the EasyFormComponent component.
意思是你在组件不存在的情况下去调用setState,而我们这个时候组件不存在了,说明是timer还在调用,所以这种卸载方式仅仅卸载了组件,而没有销毁timer。
所以正确的做法是这样:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
constructor(props){
console.log("constructor是代替getInitialState的函数");
super(props);
this.state = {
count: 0,
};
}
static defaultProps = {
message: '默认消息'
}
componentWillMount(){
console.log('componentWillMount');
var self=this;
this.timer=setInterval(function(){
self.setState({
count:self.state.count+1
})
},1000)
}
componentDidMount(){
console.log(this.refs['goodInput']);
}
componentWillUnmount(){
var info='you are tring to kill me !!';
console.log(info);
alert(info);
clearInterval(this.timer);
}
killMySelf(){
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
}
render(){
console.log('渲染');
return (
<div>
<div ref="goodInput">Hello, world!</div>;
<button onClick={this.killMySelf}>卸载掉这个组件</button>
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h3>我是子组件</h3>
<div>count:{this.props.count}</div>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
即在将要卸载组件的生命周期中去清理timer的占用。
组件的更新还会影响到子组件(如果子组件有接收父组件的响应式属性并做为其的prop)
那么shouldComponentUpdate生命周期函数中可以决定一次更新是否允许,返回为true则表示允许本次更新,否则本次更新无效。
然后接下来的生命周期函数就是将要更新componentWillUpdate函数以及更新完成componentDidUpdate这个函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
constructor(props){
console.log("constructor是代替getInitialState的函数");
super(props);
this.state = {
count: 0,
};
this.doUpdate=this.doUpdate.bind(this);
}
shouldComponentUpdate(nextProp,nextState){
console.log('shouldComponentUpdate');
//返回true则表示允许这次更新
return true;
}
componentWillUpdate(){
console.log('componentWillUpdate');
}
componentDidUpdate(){
console.log('componentDidUpdate');
}
doUpdate(){
this.setState({
count:this.state.count+1
})
}
killMySelf(){
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
}
render(){
return (
<div>
<div ref="goodInput">Hello, world!</div>;
<button onClick={this.killMySelf}>卸载掉这个组件</button>
<button onClick={this.doUpdate}>手动更新下组件(包括子组件)</button>
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h3>我是子组件</h3>
<div>count:{this.props.count}</div>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
那么比如我可以利用shouldComponentUpdate生命周期的第二个参数来控制即将到来的state的某个属性的下一次值的预判,进而进行逻辑决定是否给予本次更新。
比如我控制最大值只能是3的应用案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
constructor(props){
super(props);
this.state = {
count: 0,
};
this.doUpdate=this.doUpdate.bind(this);
}
shouldComponentUpdate(nextProp,nextState){
console.log('shouldComponentUpdate');
if(nextState.count>3){
return false;
}
return true;
}
componentWillUpdate(){
console.log('componentWillUpdate');
}
componentDidUpdate(){
console.log('componentDidUpdate');
}
doUpdate(){
this.setState({
count:this.state.count+1
})
}
killMySelf(){
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
}
render(){
return (
<div>
<div ref="goodInput">Hello, world!</div>;
<button onClick={this.killMySelf}>卸载掉这个组件</button>
<button onClick={this.doUpdate}>手动更新下组件(包括子组件)</button>
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h3>我是子组件</h3>
<div>count:{this.props.count}</div>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
这个案例或许是符合实际应用场景的正确解决方案吧。
将要接收的周期函数componentWillReceiveProps用于子组件将要接收父组件给它传递的参数的时候。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
constructor(props){
super(props);
this.state = {
count: 0,
};
this.doUpdate=this.doUpdate.bind(this);
}
shouldComponentUpdate(nextProp,nextState){
console.log('shouldComponentUpdate');
if(nextState.count>3){
return false;
}
return true;
}
componentWillUpdate(){
console.log('componentWillUpdate');
}
componentDidUpdate(){
console.log('componentDidUpdate');
}
doUpdate(){
this.setState({
count:this.state.count+1
})
}
killMySelf(){
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
}
render(){
return (
<div>
<div ref="goodInput">Hello, world!</div>;
<button onClick={this.killMySelf}>卸载掉这个组件</button>
<button onClick={this.doUpdate}>手动更新下组件(包括子组件)</button>
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
componentWillReceiveProps(nextProp){
console.log('子组件将要获得prop');
}
render(){
return (
<div>
<h3>我是子组件</h3>
<div>count:{this.props.count}</div>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
以及shouldComponentUpdate也能子组件使用,并在子组件中第二个参数做为子组件在将要接收prop后的周期函数的时候决定是否允许本次子组件的prop的接收,那么基于此我们就可以让父组件的state的某个int型属性不断递增,而传递到子组件的prop确能受控制,例如我这里的一个例子让父组件的state的count不断递增,而子组件的prop的count最多只能是5。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bower_components/react/react.development.js"></script>
<script src="bower_components/react/react-dom.development.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
class EasyFormComponent extends React.Component{
constructor(props){
super(props);
this.state = {
count: 0,
};
this.doUpdate=this.doUpdate.bind(this);
}
shouldComponentUpdate(nextProp,nextState){
return true;
}
componentWillUpdate(){
console.log('componentWillUpdate');
}
componentDidUpdate(){
console.log('componentDidUpdate');
}
doUpdate(){
this.setState({
count:this.state.count+1
})
}
killMySelf(){
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
}
render(){
return (
<div>
<h3>我是父组件</h3>
<div>count:{this.state.count}</div>
<button onClick={this.killMySelf}>卸载掉这个组件</button>
<button onClick={this.doUpdate}>手动更新下组件(包括子组件)</button>
<ChildComponent count={this.state.count} />
</div>
);
}
}
//子组件
class ChildComponent extends React.Component{
componentWillReceiveProps(nextProp){
console.log('子组件将要获得prop');
}
shouldComponentUpdate(nextProp,nextState){
console.log("shouldComponentUpdate");
if(nextProp.count>5){
return false;
}
return true;
}
render(){
return (
<div>
<h3>我是子组件</h3>
<div>count:{this.props.count}</div>
</div>
);
}
}
ReactDOM.render(<EasyFormComponent />, document.getElementById('app'));
</script>
</body>
</html>
关键字词:组件,生命周期