[关闭]
@brizer 2016-01-30T21:03:22.000000Z 字数 6375 阅读 1395

React之组件的生命周期


前言

前面学习了组件的基本API,本文主要学习React中组件的生命周期。并对每一个阶段的触发事件进行详细学习。


生命周期

组件的生命周期包含三个主要部分:

挂载: 组件被插入到DOM中。
更新: 组件被重新渲染,查明DOM是否应该刷新。
移除: 组件从DOM中移除。

React提供生命周期方法,你可以在这些方法中放入自己的代码。我们提供will方法,会在某些行为发生之前调用,和did方法,会在某些行为发生之后调用。

挂载阶段

getInitialState(): object在组件被挂载之前调用。状态化的组件应该实现这个方法,返回初始的state数据

componentWillMount(): 在挂载发生之前立即被调用。

componentDidMount(): 在挂载结束之后马上被调用。需要DOM节点的初始化操作应该放在这里。

更新阶段

componentWillReceiveProps(object nextProps): 当一个挂载的组件接收到新的props的时候被调用。该方法应该用于比较this.propsnextProps,然后使用this.setState()来改变state。

shouldComponentUpdate(object nextProps, object nextState): 当组件做出是否要更新DOM的决定的时候被调用。实现该函数,优化this.propsnextProps,以及this.statenextState的比较,如果不需要React更新DOM,则返回false

componentWillUpdate(object nextProps, object nextState): 在更新发生之前被调用。你可以在这里调用this.setState()

componentDidUpdate(object prevProps, object prevState): 在更新发生之后调用。

移除阶段

componentWillUnmount(): 在组件移除和销毁之前被调用。清理工作应该放在这里。


方法

接下来我们一一学习呢。

getDefaultProps

该方法是所有我们提及的方法中最先触发的,你可以在该方法里 return 一个对象来作为组件默认的Props值(当然如果父组件传进来了props,则以传进来的为主),它只在组件初次挂载到页面上时触发一次,即使你重新挂载了组件。

getInitialState

用于给组件初始化state的值,调用该方法要求必须 return 一个对象或者null,否则会报错。该方法在组件每次实例化(也就是挂载的时候都会触发

componentWillMount

在组件挂载之前执行操作,但仅执行一次,即使多次重复渲染该组件,或者改变了组件的state:

  1. var i = 0;
  2. var Component1 = React.createClass({
  3. componentWillMount: function(){
  4. console.log(i++)
  5. },
  6. getInitialState: function() {
  7. return {
  8. isClick: !1
  9. }
  10. },
  11. clickCb: function() {
  12. this.setState({
  13. isClick : !0
  14. })
  15. },
  16. render: function() {
  17. return <div onClick={this.clickCb}>isClick:{this.state.isClick? 'yes' : 'nope'}</div>
  18. }
  19. });
  20. var div = document.getElementById('a');
  21. React.render(
  22. <Component1 />,div
  23. );
  24. React.render(
  25. <Component1 />,div
  26. );

i会一直保持0。除非我们使用 React.unmountComponentAtNode移除组件,再渲染。

  1. var div = document.getElementById('a');
  2. React.render(
  3. <Component1 />,div
  4. );
  5. React.unmountComponentAtNode(div); //移除掉已有组件
  6. React.render(
  7. <Component1 />,div
  8. );

就可以再次调用componentWillMount中的方法。

componentDidMount

顾名思义可以猜到这个是在组件初始化挂载之后执行的。

componentWillMount 一样,同一个组件重复渲染只执行一次,卸载组件后重新渲染可以重新触发一次:

  1. var i = 0,
  2. div = document.getElementById('a'),
  3. div2 = document.getElementById('b');
  4. var Component1 = React.createClass({
  5. componentDidMount: function(){
  6. console.log(i++)
  7. },
  8. clickCb: function() {
  9. React.render(
  10. <Component1 />, div2
  11. );
  12. },
  13. render: function() {
  14. return <div onClick={this.clickCb}>点我给下一个div挂载组件</div>
  15. }
  16. });
  17. React.render(
  18. <Component1 />, div
  19. );
  20. //React.unmountComponentAtNode(div); //移除掉已有组件
  21. React.render(
  22. <Component1 />, div
  23. );

点击div1时会将组件挂载到div2上,触发div2的组件的 componentDidMount 回调(毕竟div1和div2上的组件并非同一个)

componentWillReceiveProps

在组件接收到新props的时间点之前调用,注意组件初始化渲染时则不会执行:

  1. var i = 0,
  2. div = document.getElementById('a'),
  3. div2 = document.getElementById('b');
  4. var Component1 = React.createClass({
  5. componentWillReceiveProps: function(){
  6. console.log(i++)
  7. },
  8. clickCb: function() {
  9. React.render(
  10. <Component1 />, div2
  11. );
  12. },
  13. render: function() {
  14. return <div onClick={this.clickCb}>点我给下一个div挂载组件</div>
  15. }
  16. });
  17. React.render(
  18. <Component1 />, div //初始化不会触发componentWillReceiveProps
  19. );
  20. React.render(
  21. <Component1 />, div //重复渲染会触发componentWillReceiveProps
  22. );
  23. React.unmountComponentAtNode(div); //移除掉已有组件
  24. React.render(
  25. <Component1 />, div //初始化不会触发componentWillReceiveProps
  26. );

我们移除掉组件再挂载的时候,相当于重新初始化渲染了组件(得到的props是初始化props而不是新props),故不会触发 componentWillReceiveProps

而当我们在div2挂载了组件后再点击div2来重新渲染它的组件,会触发 componentWillReceiveProps

该方法有一个参数 nextProps,我们可以利用它来获取新 props 的值(this.props 获取到的是当前的,也就是旧的 props):

  1. var i = 0,
  2. div = document.getElementById('a'),
  3. render = function(){
  4. React.render(
  5. <Component1 i={i++} />, div
  6. );
  7. };
  8. var Component1 = React.createClass({
  9. componentWillReceiveProps: function(nextProps){
  10. console.log(this.props.i, nextProps.i)
  11. },
  12. render: function() {
  13. return <div onClick={render}>props.i的值是:{this.props.i}</div>
  14. }
  15. });
  16. render();

shouldComponentUpdate

该方法在组件接收到了新的 props 或者新的 state 的时候(该时间点render还没执行哦)会立即调用,然后通过返回值(Boolean)来决定是否要重新渲染当前的组件。

该方法带有两个参数,第一个参数表示新的props,第二个参数表示新的state。

模拟现在要求div要点击3次之后,才重新渲染自身组件:

  1. var div = document.getElementById('a');
  2. var Component1 = React.createClass({
  3. getInitialState: function(){
  4. return { i : 0 }
  5. },
  6. shouldComponentUpdate: function(nextProps, nextState){
  7. console.log( this.state.i, nextState.i );
  8. return nextState.i > 3 ? true : false; //返回true才会渲染组件
  9. },
  10. clickCb: function(){
  11. this.setState({
  12. i : this.state.i + 1
  13. })
  14. },
  15. render: function() {
  16. return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div>
  17. }
  18. });
  19. React.render(
  20. <Component1 />, div
  21. );

效果如下:

componentWillUpdate

shouldComponentUpdate 一样,在组件收到新的 props 或者 state 的时候会立即调用,而且也有着俩个参数来获取新的 props 和 state。

不过本方法会在 shouldComponentUpdate 执行并返回了 true 的时候才会被调用。我们拿上一个代码示例做点小修改:

  1. var div = document.getElementById('a');
  2. var Component1 = React.createClass({
  3. getInitialState: function(){
  4. return { i : 0 }
  5. },
  6. shouldComponentUpdate: function(nextProps, nextState){
  7. console.log( this.state.i, nextState.i );
  8. return nextState.i > 3 ? true : false; //返回true才会执行componentWillUpdate并重新渲染组件
  9. },
  10. componentWillUpdate: function(nextProps, nextState){
  11. console.log( 'yoyoyo', this.state.i, nextState.i );
  12. },
  13. clickCb: function(){
  14. this.setState({
  15. i : this.state.i + 1
  16. })
  17. },
  18. render: function() {
  19. return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div>
  20. }
  21. });
  22. React.render(
  23. <Component1 />, div
  24. );

效果如下:

componentDidUpdate

该方法会在组件更新、重新渲染完毕了之后才触发,它和 componentWillUpdate 一样有着俩个参数来获取新的 props 和 state。

  1. var div = document.getElementById('a');
  2. var Component1 = React.createClass({
  3. getInitialState: function(){
  4. return { i : 0 }
  5. },
  6. shouldComponentUpdate: function(nextProps, nextState){
  7. console.log( this.state.i, nextState.i );
  8. return nextState.i > 3 ? true : false; //返回true才会执行componentWillUpdate并重新渲染组件
  9. },
  10. componentDidUpdate: function(nextProps, nextState){
  11. console.log( '已经渲染完毕咯', this.state.i, nextState.i );
  12. },
  13. componentWillUpdate: function(nextProps, nextState){
  14. console.log( '还没渲染哦', this.state.i, nextState.i );
  15. },
  16. clickCb: function(){
  17. this.setState({
  18. i : this.state.i + 1
  19. })
  20. },
  21. render: function() {
  22. return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div>
  23. }
  24. });
  25. React.render(
  26. <Component1 />, div
  27. );

效果如下:

componentWillUnmount

组件要被移除之前的时间点触发,可以利用该方法来执行一些必要的清理,比如清除无效的定时器,或者清除在 componentDidMount 中创建的 DOM 元素等:

  1. var div = document.getElementById('a'),
  2. div2 = document.getElementById('b');
  3. var Component1 = React.createClass({
  4. DOMArr : [],
  5. getInitialState: function(){
  6. return { i : 0 }
  7. },
  8. componentDidUpdate: function(nextProps, nextState){
  9. var dom = document.createElement('p');
  10. dom.innerText = this.state.i;
  11. div2.appendChild(dom);
  12. this.DOMArr.push(dom);
  13. },
  14. componentWillUnmount: function(){
  15. if(!this.DOMArr.length) return;
  16. var i = 0;
  17. while(i < this.DOMArr.length){console.log(i);
  18. div2.removeChild(this.DOMArr[i++]); //移除componentDidUpdate里添加过的DOM
  19. }
  20. },
  21. clickCb: function(){
  22. this.setState({
  23. i : this.state.i + 1
  24. })
  25. },
  26. render: function() {
  27. return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div>
  28. }
  29. });
  30. React.render(
  31. <Component1 />, div
  32. );
  33. div2.addEventListener('click',function(){
  34. React.unmountComponentAtNode(div) //点击div2则卸载掉第一个div里的组件
  35. }, false)

效果如下:


最后理一下全部的触发顺序:


参考

浏览器中工作原理
组件详细说明和生命周期
React入门系列

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注