React Component 常用生命周期函数: getInitialState -> WillMount -> render -> DidMount -> DidUpdate(WillReceiveProps)->WillUnMount
挂载(mount):React的特点是先生成Virtual DOM,再把这个Virtual DOM在真实的DOM上画出来,这个行为就叫挂载。只有挂载后,React元素才可以在真实的DOM(也即浏览器的doument)中找到。
实际应用:
getInitialState
在组件初始化时调用一次,仅调用一次
示例代码如下:
1 | getInitialState() { |
则在别的组件函数中,可以通过this.state.itemList
来引用变量。
注意事项:
1.如果要改变state
,请使用React的setState
方法。 在本例中为:this.setState({itemList: newList})
,不要直接对state
赋值,如:this.state.itemList = newList
. 因为前者会触发一次render
的调用(即组件重新渲染),而后者却不会,这不是正确的使用方式。
2.React并不保证setState
调用后立即改变state
的状态。
3.setState
其实还有回调。如:
1 | this.setState({ |
compoentWillMount
在组件挂载前调用一次,仅调用一次
我一般在这里用ajax
获取数据,之后再通过setState
引起组件的重新渲染。
例子:
1 | //获取商品详情信息 |
提示:
组件在getInitialState
后render
一次,如果WillMount
里调用了setState
, 则又会组件引起render
一次。则组件一共调用render
了两次。
componentDidMount
在组件挂载后调用一次,仅调用一次
此时元素节点已经在真实的DOM中生成了,可以绑定事件了。
例子:
1 | componentDidMount() { |
注意:
1.React.findDOMNode(this.refs.xxx)
是React自带的查找节点的方法,它查找的是虚拟DOM里的节点,也即无论组件挂载前后,它都可以查找到节点
2.用第三方类库如Zepto, 使用$(selector)
来查询,它查找的是真实的DOM节点,只有在节点挂载后才可以查找到, 也只有此时添加监听事件才生效
3.虚拟DOM的节点可以被$查询包装起来,如 let $btns = $(R.findDOMNode(this.refs.btns));
, 同样的,也只节点挂载后这样才有用,不然查询出来的只是个空集合。
4.注意上面的用词是节点挂载后,不是组件挂载后,组件里包含了节点,但组件DidMount
了不一定节点就挂载了,这在复杂的一点的业务场景下是可能的(比如组件在DidMount
利用ajax
获取数据,之后再setState
,则由此生成的节点要等组件触发DidUpdate
事件时才算挂载成功)。
componentDidMount的陷阱
1 | getInitialState() { |
实践过程中发现,在code1
及code2
中st.goodsIdAndNumList
是个空数组,而在code2
中this.state.goodsIdAndNumList
才有值。这表明:
1.WillMount
虽然先于DidMount
执行,但它们默认是异步的,即后者不会因为前者未执行完成就等待。因此WillMount
里使用ajax
获取数据期间,DidMount
就已经执行完毕了,故此时code1
中st
并未得到更新。
2.code2
中st.goodsIdAndNumList
仍为空数组。按道理来说st
应该是引用,但事实表明,它是只是值。
对此我猜测,DidMount
的时候通过this.state
获取的只是组件的state
的值的一个副本,当之后state
再改变时,DidMount
里的this.state
并不会改变,因为state
的改变已经反应在DidUpate
函数中了。
componentDidUpdate(prevProps, prevState)
新的props或state已经同步到真实的DOM后立即调用,在初始化渲染的时候,该方法不会调用。
注意:
新的props
和state
都会触发该方法,也即在子组件中该方法通常会被频繁触发。如果要在该方法中做绑定事件,最好判断清楚此次update
究竟是来自props
还是来自state
,否则会绑定多次。不过,有一个偷懒的方法,那就是在绑定事件前先解绑,例子如下:
1 | componentDidUpdate: function () { |
componentWillReceiveProps(nextProps)
接收到新的props
时触发;对于子组件而言,是父组件重新渲染时触发。在初始化渲染的时候,该方法不会调用。
注意:
对于子组件而言,触发该函数时,父组件传来的props
有可能与上一次的props
是一样的。更详细的说明,请看官方博客
死循环的经历:
父组件传了一个方法给子组件,该方法调用了setState
,会引起父组件的重新渲染,也会触发componentWillReceiveProps
方法。
而我在componentWillReceiveProps
方法中未做nextProps
与this.props
的判断,直接就调用父组件传过来的方法,引起父组重新渲染,重新触发子组件的componentWillReceiveProps
,再次调用父组件传过来的方法,于是就死循环了。
render
通过React.createClass()
或extends React.Component
创建的组件必须包含render
方法。
render
方法里一般根据state
或props
来渲染组件。render
里面可以传变量,如要做一些逻辑判断,你会发现三元表达式大有用场,更多的例子,请看官方文档
例子:
1 | render() { |
注意:
1.render
方法里不允许setState
,原因很简单,setState
会触发新的render
,允许你setState
,那就死循环啦。
2.父组件重新render
一次,会引起下面的全部子组件重新render
一次。
shouldComponentUpdate(nextProps, nextState)
该方法执行于render之前, 必须要有一个返回值. 返回true, 则会执行render, 返回false则不执行render.
如果没有返回值, 则相当于返回undefined, 会报错
不想每次state的改变都引起组件的重新渲染时, 可以自定义此方法