React系列---React(一)初识React
React系列---React(二)组件的prop和state
React系列---之React(三)组件的生命周期react
React严格定义了组件的生命周期,共3个过程:
1) 装载过程(Mount):组件第一次在DOM树中渲染的过程;
2) 更新过程(Update):组件被从新渲染的过程;
3) 卸载过程(Unmount):组件从DOM树中删除的过程。git
三种不一样的过程,React库会依次调用组件的一些生命周期函数。因此,定义一个React组件,实际上就是定制这些生命周期函数。github
装载过程依次调用的生命周期函数:
constructor getInitialState getDefaultProps
componentWillMount
render
componentDidMountsegmentfault
ES6中每一个类的构造函数,创造一个组件实例,固然会调用对应的构造函数。浏览器
并非每一个组件都须要定义构造函数。后面会看到无状态React组件是不须要定义构造函数的。
React组件须要构造函数,是为了如下目的:
1) 初始化state,由于生命周期中任何函数都有可能访问state,构造函数是初始化state的理想场所;
2) 绑定成员函数的this环境。函数
这2个函数,只有在经过React.createClass方法创造的组件类才会发生做用。这是过期的方法,ES6创造的组件中用不到。性能
假如用React.createClass定义组件Sample,设定内部状态foo初始值为bar,同时设定sampleProp的prop初始值为0,代码以下:this
const Sample = React.createClass({ getInitialState: function(){ return {foo: 'bar'}; }, getDefaultProps: function() { return {sampleProp: 0} } });
用ES6的话,在构造函数中给this.state赋值完成状态初始化,给类的属性defaultProps赋值指定props初始值:spa
class Sample extends React.Component { constructor(props) { super(props); this.state = {foo: 'bar'}; } } Sample.defaultProps = { return {sampleProp: 0}; };
React组件能够忽略其余全部函数都不实现,可是必定要实现render函数,由于全部React组件的父类React.Component类对除render以外的生命周期函数都有默认实现。render函数并不作实际的渲染动做,它只负责返回一个JSX描述的结构,最终由React来操做渲染过程。code
render函数应该是一个纯函数,彻底根据this.state和this.props来决定返回的结果,并且不要产生任何反作用。在render函数中去调用this.setState是错误的,由于一个纯函数不该该引发状态的变化。
装载过程当中,componentWillMount和componentDidMount分别在render以前和以后调用。
不过,一般不定义componentWillMount函数,由于顾名思义,它发生在将要装载的时候,这个时候一切都迟了,即便再调用this.setState()修改状态也不会引起从新绘制了。换句话说,全部能够在componentWillMount中作的事情,均可以提早到constructor中去作。能够认为这个函数存在的目的就是为了和componentDidMount对称。
而componentDidMount做用就大了。不过要注意的是,componentDidMount被调用时,前置render函数返回的东西一定已经完成了渲染,组件已经被“装载”到DOM树上了。
仍是以ControlPanel为例,在ControlPanel中有三个Counter组件,咱们修改Counter代码,让装载过程的全部生命周期函数都用console.log输出函数名和caption值,好比,componentWillMount函数以下:
componentWillMount() { console.log('enter componentWillMount ' + this.props.caption); }
在浏览器的console里咱们能看到:
enter constructor: First enter componentWillMount First enter render First enter constructor: Second enter compomentWillMount: Second enter render Second enter constructor: Third enter componentWillMount Third enter render Third enter componentDidMount First enter componentDidMount Second enter componentDidMount Third
能够清楚的看到,因为渲染须要必定的时间,因此三个组件的componentDidMount是在最后才连在一块儿被调用的。
componentWillMount和componentDidMount还有一个区别,就是componentWillMount能够在服务端被调用,也能够在浏览器端被调用;而componentDidMount只能在浏览器端被调用。
componentDidMount中,可经过AJAX获取数据来填充组件内容。在componentDidMount被调用时,组件已经被装载到DOM树了,也能够放心的让React和其余操纵DOM的库(如jQuery)配合工做了。
当组件被装载到DOM树上以后,用户在网页上看到了第一印象,可是要提供更好的交互体验,就要让组件能够随着用户操做改变展示的内容,当props或state被修改时,就会引起组件的更新过程。
更新过程依次调用如下生命周期函数:
1) componentWillReceiveProps
2) shouldComponentUpdate
3) componentWillUpdate
4) render
5) componentDidUpdate
当组件的props发生改变时会被调用。父组件的render被调用时,被渲染的子组件也会经历更新过程,无论父组件传给子组件的props有没有改变,都会触发子组件的componentWillReceiveProps。
咱们在Counter组件类里增长这个函数定义,并在console输出一些文字:
componentWillReceiveProps(nextProps) { console.log('enter componentWillReceiveProps ' + this.props.caption) }
在ControlPanel组件的render函数中,也作以下修改:
render() { console.log('enter ControlPanel render'); return ( <div style={style}> ... <button onClick={ () => this.forceUpdate() }> Click me to parent! </button> </div> ); }
除了在ControlPanel的render函数入口增长console输出,还增长了一个按钮,当这个按钮被点击时,调用this.forceUpdate(),每一个React组件均可以经过forceUpdate()强行引起一次组件重绘。
在网页上点击父组件新增的重绘按钮,看到浏览器console输出:
enter ControlPanel render enter componentWillReceiveProps First enter render First enter componentWillReceiveProps Second enter render Second enter componentWillReceiveProps Third enter render Third
能够看到,父组件引起重绘后,首先是父组件ControllPanel的render被调用,随后依次3个Counter子组件的componentWillReceiveProps和render函数被调用。
然而,父组件传给三个子组件的props值一直没有变化,这就验证了componentWillReceiveProps并不仅是当props值变化时才被调用,父组件render时,子组件的componentWillReceiveProps也会被调用。
在网页中,咱们再尝试点击第一个Counter子组件的“+”按钮,能够看到浏览器console输出:
enter render First
明显,只有第一个子组件Counter的render函数被调用,由于组件的this.setState()函数不会引起componentWillReceiveProps调用。
shouldComponentUpdate函数返回一个布尔值,告诉React库这个组件在此次更新过程当中是否要继续。返回false会中止更新过程,就此结束,也不会引起后续的渲染了。
这个函数可以大大提高React组件的性能,无论React的组件渲染有多快,若是发现没有必要从新渲染,就干脆不要渲染。
修改Counter组件类增长shouldComponentUpdate函数的定义:
shouldComponentUpdate(nextProps, nextState) { return (nextProps.caption !== this.props.caption) || (nextState.count !== this.state.count); }
若是组件的shouldComponentUpdate返回true,接下来会依次调用componentWillUpdate、render和componentDidUpdate函数。
在介绍componentDidMount函数时,说到能够利用componentDidMount函数执行其余UI代码库,好比jQuery代码。那么如今,组件被更新时,也须要在componentDidUpdate函数再次调用jQuery代码。
React组件的卸载过程只涉及一个函数componentWillUnmount,这个函数适合作一些清理工做。这些清理工做每每和componentDidMount有关,好比你在componentDidMount中用非React的方法创造了一些DOM元素,若是撒手无论会形成内存泄漏,那就须要在componentWillUnmount中把这些DOM元素清理掉。
代码:https://github.com/zhutx/reac...
React系列---React(一)初识React
React系列---React(二)组件的prop和stateReact系列---之React(三)组件的生命周期