react组件生命周期详解

React严格定义了组建的生命周期,生命周期可能会经历三个阶段。

1、装载过程(Mount)

说明:组件第一次在DOM中渲染的过程
对应函数:
- constructor
- getInitialState
- getDefountProps
- componentWillMount
- render
- componentDidMount

1.1 constructor构造函数

初始化时被调用,声明构造函数有三个目的:
①继承父组件的props
    super(props)
②初始化组件需要的state
    this.state={变量名:值}
③成员函数绑定this环境
    this.函数名称 = this.函数名称.bind(this);
    这样做的目的在于,在render中调用时,可直接使用this.函数名称。

1.2 getInitialState和getDefountProps

getInitialState和getDefaultProps只在React.createClass方法中用到,如下定义声明class中。

const Sample=React.createClass({
    getInitialState:function(){
        return {foo:'bar'}
    },
    getDefaultProps:function(){
    return {sampleProp:0}
    }
})



因此在目前常见的组件声明方式中,getInitialState和getDefaultProps是不会被调用的。
常见的组件生命方式如下。

import React, { Component} from 'react';
//此处引用前,需要先npm install prop-types --save
import PropTypes from "prop-types";

class Counter extends Component {
  constructor(props) {
    super(props);
  //定义初始化state,相当于getInitialState
   this.state = {
      count: props.initValue
    }
  }
//定义默认的Props相当于getDefaultProps
Counter.defaultProps = {
  return{sampleProps:0}
};


1.3 render

render需要注意两点:
    ①render是纯函数,他根据this.state和this.props来决定返回结果;
    ②render 不做实际的渲染动作,它返回的jsx描述的结构,交给React来操作渲染。

1.4 componentWillMount和componentDidMount

实际上根据名称就可发现componentWillMount是在render之前调用,componentDidMount是在render之后调用。
注意:按顺序加载是componentWillMount->render->componentDidMount,但如果在componentWillMount进行网络请求,便有可能先加载render,因为react的思想便是异步加载。

案例说明:

父组件ControlPanel .js

import React, { Component } from 'react';
//引入子组件
import Counter from './Counter.js';
const style = {
  margin: '20px'
};
class ControlPanel extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    console.log('enter ControlPanel render');
    return (
      <div style={style}>
      //按引用名称使用子组件
        <Counter  caption="First" />
        <Counter caption="Second" initValue={10}/>
        <Counter caption="Third" initValue={20} />
      </div>
    );
  }
}
export default ControlPanel;



子组件Counter.js

import React, { Component} from 'react';
//同上PropTypes 引用说明
import PropTypes from "prop-types";
const buttonStyle = {
  margin: '10px'
};
class Counter extends Component {
  constructor(props) {
    console.log('enter constructor: ' + props.caption);
    super(props);

    this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
    this.onClickDecrementButton = this.onClickDecrementButton.bind(this);

    this.state = {
      count: props.initValue
    }
  }
  componentWillMount() {
    console.log('enter componentWillMount ' + this.props.caption);
  }
  componentDidMount() {
    console.log('enter componentDidMount ' + this.props.caption);
  }
  onClickIncrementButton() {
    this.setState({count: this.state.count + 1});
  }
  onClickDecrementButton() {
    this.setState({count: this.state.count - 1});
  }
  render() {
    console.log('enter render ' + this.props.caption);
    const {caption} = this.props;
    return (
      <div>
        <button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
        <button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
        <span>{caption} count: {this.state.count}</span>
      </div>
    );
  }
}
//propTypes是对父组件传入的值类型的一个限制
Counter.propTypes = {
  caption: PropTypes.string.isRequired,
  initValue: PropTypes.number
};
//与constructor中初始化state类似,若父页面没有传入prop对应的值,在此处便对prop值进行了初始化定义
Counter.defaultProps = {
  initValue: 0
};
export default Counter;



在如上的案例加载中,console的打印结果如下:
enter ControlPanel render
enter constructor: First
enter componentWillMount First
enter render First
enter constructor: Second
enter componentWillMount Second
enter render Second
enter constructor: Third
enter componentWillMount Third
enter render Third
enter componentDidMount First
enter componentDidMount Second
enter componentDidMount Third


产生这一现象的原因是,render函数本身并不往DOM中渲染或者装载内容,它只会返回一个JSX所表示的对象,然后由React库来根据返回对象决定如何渲染。而React库要把所有组件返回的结果综合起来,才知道如何产生对应的DOM。因此在分别调用了三个render之后,才回依次加载componentDidMount。

2、更新过程(Update)

说明:组件被重新渲染的过程
对应函数:
- componentWillReceiveProps(nextProps)
- shouldComponentUpdate(nextProps,nextState)
- componentWillUpdate
- render
- componentDidUpdate


2.1 componentWillReceiveProps(nextProps)

在父组件render函数调用时,render函数中渲染的子组件都会经历更新,无论父组件加载过程中传入的props有无发生改变,均会触发子组件的componentWillReceiveProps函数加载。

在父组件ControlPanel .js加入如下代码

 render() {
    console.log('enter ControlPanel render');
    return (
      <div style={style}>
       ……
        <button onClick={() => this.forceUpdate()}>//forceUpdate强制更新,加载render
          Click me to re-render!
        </button>
      </div>



在子组件Counter.js中加入如下代码

  componentWillReceiveProps(nextProps) {
    console.log('enter componentWillReceiveProps ' + this.props.caption)
  }



console输出内容为
enter ControlPanel render
enter componentWillReceiveProps First
enter render First
enter componentWillReceiveProps Second
enter render Second
enter componentWillReceiveProps Third
enter render Third
当父组件更新加载render时,会触发子组件加载componentWillReceiveProps 函数。

2.2 shouldComponentUpdate(nextProps,nextState)

shouldComponentUpdate函数的重要程度仅次于render,因为该函数决定了组件什么时候不需要更新渲染。
render和shouldComponentUpdate函数均有返回值。render返回结果将用于构造DOM对象,shouldComponentUpdate返回布尔值,告诉react库这个组件在这次更新过程中是否要继续,即是否继续加载render、componentWillUpdate和componentDidUpdate。若为false,则无需进行下一步加载,若为true,则需要更新加载render。


在子组件Count.js中加入如下代码

shouldComponentUpdate(nextProps, nextState) {//它决定了是否要渲染render
    return (nextProps.caption !== this.props.caption) ||
           (nextState.count !== this.state.count);
  }



单击按钮,console输出内容为
enter ControlPanel render
enter componentWillReceiveProps First
enter componentWillReceiveProps Second
enter componentWillReceiveProps Third
输出结果呈现,shouldComponentUpdate中判断了caption 和count,没有发生改变,返回了false,因此未更新加载render。

2.3 componentWillUpdate和componentDidUpdate

componentWillUpdate、componentDidUpdate和componentWillMount、componentDidMount相似。

在子组件Count.js中暂时注释掉shouldComponentUpdate代码,加入componentWillUpdate和componentDidUpdate。

  // shouldComponentUpdate(nextProps, nextState) {//它决定了是否要渲染render
  //   return (nextProps.caption !== this.props.caption) ||
  //          (nextState.count !== this.state.count);
  // }
  componentWillUpdate(){
    console.log('enter componentWillUpdate ' + this.props.caption);
  }
  componentDidUpdate(){
    console.log('enter componentDidUpdate ' + this.props.caption);
  }



单击按钮,console输出内容为
enter ControlPanel render
enter componentWillReceiveProps First
enter componentWillUpdate First
enter render First
enter componentWillReceiveProps Second
enter componentWillUpdate Second
enter render Second
enter componentWillReceiveProps Third
enter componentWillUpdate Third
enter render Third
enter componentDidUpdate First
enter componentDidUpdate Second
enter componentDidUpdate Third
输出结果呈现,在更新过程中,优先加载componentWillUpdate 和render,所有render加载完成之后,挂载到DOM后,再加载componentDidUpdate。

3、卸载过程(Unmount)

说明:组件从DOM中删除的过程
对应函数:

  • componentWillUnmount

componentWillUnmount一般用于组件从DOM树上删除掉之前。


4、总结

熟悉react生命周期函数,有利于在使用过程中进行更好的调用,因此做了此篇博客,以供大家参考。

猜你喜欢

转载自blog.csdn.net/zfan520/article/details/78954327