@brizer
2016-01-30T21:03:22.000000Z
字数 6375
阅读 1422
前面学习了组件的基本API,本文主要学习React中组件的生命周期。并对每一个阶段的触发事件进行详细学习。
组件的生命周期包含三个主要部分:
挂载: 组件被插入到DOM中。
更新: 组件被重新渲染,查明DOM是否应该刷新。
移除: 组件从DOM中移除。
React提供生命周期方法,你可以在这些方法中放入自己的代码。我们提供will方法,会在某些行为发生之前调用,和did方法,会在某些行为发生之后调用。
getInitialState()
: object在组件被挂载之前调用。状态化的组件应该实现这个方法,返回初始的state数据。
componentWillMount()
: 在挂载发生之前立即被调用。
componentDidMount()
: 在挂载结束之后马上被调用。需要DOM节点的初始化操作应该放在这里。
componentWillReceiveProps(object nextProps)
: 当一个挂载的组件接收到新的props的时候被调用。该方法应该用于比较this.props
和nextProps
,然后使用this.setState()
来改变state。
shouldComponentUpdate(object nextProps, object nextState):
当组件做出是否要更新DOM的决定的时候被调用。实现该函数,优化this.props
和nextProps
,以及this.state
和nextState
的比较,如果不需要React更新DOM,则返回false。
componentWillUpdate(object nextProps, object nextState)
: 在更新发生之前被调用。你可以在这里调用this.setState()
。
componentDidUpdate(object prevProps, object prevState)
: 在更新发生之后调用。
componentWillUnmount()
: 在组件移除和销毁之前被调用。清理工作应该放在这里。
接下来我们一一学习呢。
该方法是所有我们提及的方法中最先触发的,你可以在该方法里 return 一个对象来作为组件默认的Props值(当然如果父组件传进来了props,则以传进来的为主),它只在组件初次挂载到页面上时触发一次,即使你重新挂载了组件。
用于给组件初始化state的值,调用该方法要求必须 return 一个对象或者null,否则会报错。该方法在组件每次实例化(也就是挂载)的时候都会触发。
在组件挂载之前
执行操作,但仅执行一次,即使多次重复渲染该组件,或者改变了组件的state:
var i = 0;
var Component1 = React.createClass({
componentWillMount: function(){
console.log(i++)
},
getInitialState: function() {
return {
isClick: !1
}
},
clickCb: function() {
this.setState({
isClick : !0
})
},
render: function() {
return <div onClick={this.clickCb}>isClick:{this.state.isClick? 'yes' : 'nope'}</div>
}
});
var div = document.getElementById('a');
React.render(
<Component1 />,div
);
React.render(
<Component1 />,div
);
i会一直保持0。除非我们使用 React.unmountComponentAtNode
移除组件,再渲染。
var div = document.getElementById('a');
React.render(
<Component1 />,div
);
React.unmountComponentAtNode(div); //移除掉已有组件
React.render(
<Component1 />,div
);
就可以再次调用componentWillMount
中的方法。
顾名思义可以猜到这个是在组件初始化挂载之后执行
的。
同 componentWillMount
一样,同一个组件重复渲染只执行一次
,卸载组件后重新渲染可以重新触发一次:
var i = 0,
div = document.getElementById('a'),
div2 = document.getElementById('b');
var Component1 = React.createClass({
componentDidMount: function(){
console.log(i++)
},
clickCb: function() {
React.render(
<Component1 />, div2
);
},
render: function() {
return <div onClick={this.clickCb}>点我给下一个div挂载组件</div>
}
});
React.render(
<Component1 />, div
);
//React.unmountComponentAtNode(div); //移除掉已有组件
React.render(
<Component1 />, div
);
点击div1时会将组件挂载到div2上,触发div2的组件的 componentDidMount
回调(毕竟div1和div2上的组件并非同一个)
在组件接收到新props的时间点之前调用,注意组件初始化渲染时则不会执行:
var i = 0,
div = document.getElementById('a'),
div2 = document.getElementById('b');
var Component1 = React.createClass({
componentWillReceiveProps: function(){
console.log(i++)
},
clickCb: function() {
React.render(
<Component1 />, div2
);
},
render: function() {
return <div onClick={this.clickCb}>点我给下一个div挂载组件</div>
}
});
React.render(
<Component1 />, div //初始化不会触发componentWillReceiveProps
);
React.render(
<Component1 />, div //重复渲染会触发componentWillReceiveProps
);
React.unmountComponentAtNode(div); //移除掉已有组件
React.render(
<Component1 />, div //初始化不会触发componentWillReceiveProps
);
我们移除掉组件再挂载的时候,相当于重新初始化渲染了组件(得到的props是初始化props而不是新props),故不会触发 componentWillReceiveProps
。
而当我们在div2挂载了组件后再点击div2来重新渲染它的组件,会触发 componentWillReceiveProps
:
该方法有一个参数 nextProps
,我们可以利用它来获取新 props 的值(this.props 获取到的是当前的,也就是旧的 props):
var i = 0,
div = document.getElementById('a'),
render = function(){
React.render(
<Component1 i={i++} />, div
);
};
var Component1 = React.createClass({
componentWillReceiveProps: function(nextProps){
console.log(this.props.i, nextProps.i)
},
render: function() {
return <div onClick={render}>props.i的值是:{this.props.i}</div>
}
});
render();
该方法在组件接收到了新的 props 或者新的 state 的时候(该时间点render还没执行哦)会立即调用,然后通过返回值(Boolean)来决定是否要重新渲染当前的组件。
该方法带有两个参数,第一个参数表示新的props,第二个参数表示新的state。
模拟现在要求div要点击3次之后,才重新渲染自身组件:
var div = document.getElementById('a');
var Component1 = React.createClass({
getInitialState: function(){
return { i : 0 }
},
shouldComponentUpdate: function(nextProps, nextState){
console.log( this.state.i, nextState.i );
return nextState.i > 3 ? true : false; //返回true才会渲染组件
},
clickCb: function(){
this.setState({
i : this.state.i + 1
})
},
render: function() {
return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div>
}
});
React.render(
<Component1 />, div
);
效果如下:
同 shouldComponentUpdate
一样,在组件收到新的 props
或者 state
的时候会立即调用,而且也有着俩个参数来获取新的 props 和 state。
不过本方法会在 shouldComponentUpdate
执行并返回了 true 的时候才会被调用。我们拿上一个代码示例做点小修改:
var div = document.getElementById('a');
var Component1 = React.createClass({
getInitialState: function(){
return { i : 0 }
},
shouldComponentUpdate: function(nextProps, nextState){
console.log( this.state.i, nextState.i );
return nextState.i > 3 ? true : false; //返回true才会执行componentWillUpdate并重新渲染组件
},
componentWillUpdate: function(nextProps, nextState){
console.log( 'yoyoyo', this.state.i, nextState.i );
},
clickCb: function(){
this.setState({
i : this.state.i + 1
})
},
render: function() {
return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div>
}
});
React.render(
<Component1 />, div
);
效果如下:
该方法会在组件更新、重新渲染完毕了之后才触发,它和 componentWillUpdate
一样有着俩个参数来获取新的 props 和 state。
var div = document.getElementById('a');
var Component1 = React.createClass({
getInitialState: function(){
return { i : 0 }
},
shouldComponentUpdate: function(nextProps, nextState){
console.log( this.state.i, nextState.i );
return nextState.i > 3 ? true : false; //返回true才会执行componentWillUpdate并重新渲染组件
},
componentDidUpdate: function(nextProps, nextState){
console.log( '已经渲染完毕咯', this.state.i, nextState.i );
},
componentWillUpdate: function(nextProps, nextState){
console.log( '还没渲染哦', this.state.i, nextState.i );
},
clickCb: function(){
this.setState({
i : this.state.i + 1
})
},
render: function() {
return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div>
}
});
React.render(
<Component1 />, div
);
效果如下:
在组件要被移除之前的时间点触发,可以利用该方法来执行一些必要的清理,比如清除无效的定时器,或者清除在 componentDidMount
中创建的 DOM 元素等:
var div = document.getElementById('a'),
div2 = document.getElementById('b');
var Component1 = React.createClass({
DOMArr : [],
getInitialState: function(){
return { i : 0 }
},
componentDidUpdate: function(nextProps, nextState){
var dom = document.createElement('p');
dom.innerText = this.state.i;
div2.appendChild(dom);
this.DOMArr.push(dom);
},
componentWillUnmount: function(){
if(!this.DOMArr.length) return;
var i = 0;
while(i < this.DOMArr.length){console.log(i);
div2.removeChild(this.DOMArr[i++]); //移除componentDidUpdate里添加过的DOM
}
},
clickCb: function(){
this.setState({
i : this.state.i + 1
})
},
render: function() {
return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div>
}
});
React.render(
<Component1 />, div
);
div2.addEventListener('click',function(){
React.unmountComponentAtNode(div) //点击div2则卸载掉第一个div里的组件
}, false)
效果如下:
最后理一下全部的触发顺序: