React生命周期浅析

引言

关于React的生命周期API,官网,有着详细说明。但在实际写代码的过程中,这些说明不能解决所有的疑惑。 所以我列举了一些编码中常见用例,供大家参考。

示例代码如下

/*
  use case
  1. mixin中重名生命周期方法
  2. 重复React.render同个组件
  3. 从 mount 到 unmount 再到 mount
  4. 子组件两次加载
  5. 父组件update
  6. 改变子组件的包裹
*/

var IamMixinObject = {
  componentDidMount: function(){
    console.log('mixin里的componentDidMount');
  }
};

var SonClass = React.createClass({
  mixins: [IamMixinObject],
  getDefaultProps:function(){
    console.log("getDefaultProps");
  },
  componentWillReceiveProps :function(){
    console.log("componentWillReceiveProps");
  },
  getInitialState:function(){
    console.log("getInitialState");
    return {};
  },
  componentWillMount:function(){
    console.log("componentWillMount");
  },
  componentWillUpdate:function(){
    console.log("componentWillUpdate");
  },
  shouldComponentUpdate:function(){
    console.log("shouldComponentUpdate");
    return true;
  },
  render: function(){
    console.log("render");
    return null;
  },
  componentDidUpdate: function(){
    console.log('componentDidUpdate');
  },
  componentDidMount: function(){
    console.log('componentDidMount');
  },
  componentWillUnmount: function(){
    console.log('componentWillUnmount');
  }
});


// 1. mixin中重名生命周期方法
React.render(<SonClass />, document.getElementById("forTest"));
/*
  mixin里的componentDidMount 会先于 componentDidMount输出。
  其实,mixin中和组件同名的生命周期方法,都是mixin中先执行。
*/


// 2. 重复React.render同个组件
React.render(<SonClass />, document.getElementById("forTest"));
React.render(<SonClass />, document.getElementById("forTest"));
/*
  输出:
  getDefaultProps
  getInitialState
  componentWillMount
  render
  mixin里的componentDidMount
  componentDidMount

  componentWillReceiveProps
  shouldComponentUpdate
  componentWillUpdate
  render
  componentDidUpdate 
  总结:
  第二次mount同个render组件,相当于改变 组件props。
*/

// 3. 从 mount 到 unmount 再到 mount
React.render(<SonClass />, document.getElementById("forTest"));
React.unmountComponentAtNode(document.getElementById("forTest"));
React.render(<SonClass />, document.getElementById("forTest"));
/*
  输出:
  getDefaultProps
  getInitialState
  componentWillMount
  render
  mixin里的componentDidMount
  componentDidMount
  componentWillUnmount

  getInitialState
  componentWillMount
  render
  mixin里的componentDidMount
  componentDidMount
  总结:
  unmount的时候,确实调用了componentWillUnmount方法,第二次mount的时候,并没有执行getDefaultProps方法。
  是因为,getDefaultProps Invoked once and cached when the class is created。
  它在组件类创建的时候被调用一次,其返回值会被缓存。
*/


// 4. 子组件两次装载
var FatherClass = React.createClass({
  render:function(){

    return (
      <div>
        <SonClass />
        <SonClass />      
      </div>
    )
  }
});
React.render(<FatherClass />, document.getElementById("forTest"));
/*
  输出:
  getDefaultProps
  getInitialState
  componentWillMount
  render
  getInitialState
  componentWillMount
  render

  mixin里的componentDidMount
  componentDidMount
  mixin里的componentDidMount
  componentDidMount
  总结:
  发现两次componentDidMount是后面连续触发。
  这里涉及到React的batchUpdate机制,需要另一篇文章详解。
  大概机制是,
  因为setState是异步的。
  它把变化存入一个临时队列,渲染完新的内容后才调用所有 componentDidUpdate或componentDidMount。

*/

// 5. 父组件update
var FatherClass = React.createClass({
  getInitialState:function(){
    
    return {
      changeFlag:false
    };
  },
  changeSon:function(){
    var changeFlag = this.state.changeFlag;
    this.setState({
      changeFlag: !changeFlag
    });
  },
  render:function(){
    return (
      <div onClick={this.changeSon} >
        <SonClass />                
      </div>
    )
  }
});
React.render(<FatherClass />, document.getElementById("forTest"));
/*
  输出:
  getDefaultProps
  getInitialState
  componentWillMount
  render
  mixin里的componentDidMount
  componentDidMount

  componentWillReceiveProps  
  shouldComponentUpdate
  componentWillUpdate
  render
  componentDidUpdate
  总结:
  父组件setState了,对于子组件是setProps了
*/

// 6. 改变子组件的包裹
var FatherClass = React.createClass({
  getInitialState:function(){
    
    return {
      changeFlag:false
    };
  },
  changeSon:function(){
    var changeFlag = this.state.changeFlag;
    this.setState({
      changeFlag: !changeFlag
    });
  },
  render:function(){
    var changeFlag = this.state.changeFlag; 
    var Son = changeFlag ? <SonClass /> : <div>new son<SonClass /></div>

    return (
      <div onClick={this.changeSon} >
        父组件在此          
        {
            Son
        }        
      </div>
    )
  }
});
React.render(<FatherClass />, document.getElementById("forTest"));
/*
  输出:
  getDefaultProps
  getInitialState
  componentWillMount
  render
  mixin里的componentDidMount
  componentDidMount

  componentWillUnmount

  getInitialState
  componentWillMount
  render
  mixin里的componentDidMount
  componentDidMount
  总结:
  父组件setState改变了子组件的包裹,子组件相当于重新mount

*/