资讯专栏INFORMATION COLUMN

React系列---React(三)组件的生命周期

geekzhou / 1068人阅读

摘要:组件装载过程装载过程依次调用的生命周期函数中每个类的构造函数,创造一个组件实例,当然会调用对应的构造函数。组件需要构造函数,是为了以下目的初始化,因为生命周期中任何函数都有可能访问,构造函数是初始化的理想场所绑定成员函数的环境。

React系列---React(一)初识React
React系列---React(二)组件的prop和state
React系列---之React(三)组件的生命周期

React严格定义了组件的生命周期,共3个过程:
1) 装载过程(Mount):组件第一次在DOM树中渲染的过程;
2) 更新过程(Update):组件被重新渲染的过程;
3) 卸载过程(Unmount):组件从DOM树中删除的过程。

三种不同的过程,React库会依次调用组件的一些生命周期函数。所以,定义一个React组件,实际上就是定制这些生命周期函数。

组件装载过程

装载过程依次调用的生命周期函数:
constructor
getInitialState
getDefaultProps
componentWillMount
render
componentDidMount

constructor

ES6中每个类的构造函数,创造一个组件实例,当然会调用对应的构造函数。

并不是每个组件都需要定义构造函数。后面会看到无状态React组件是不需要定义构造函数的。

React组件需要构造函数,是为了以下目的:
1) 初始化state,因为生命周期中任何函数都有可能访问state,构造函数是初始化state的理想场所;
2) 绑定成员函数的this环境。

getInitialState和getDefaultProps

这2个函数,只有在通过React.createClass方法创造的组件类才会发生作用。这是过时的方法,ES6创造的组件中用不到。

假如用React.createClass定义组件Sample,设定内部状态foo初始值为bar,同时设定sampleProp的prop初始值为0,代码如下:

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

用ES6的话,在构造函数中给this.state赋值完成状态初始化,给类的属性defaultProps赋值指定props初始值:

class Sample extends React.Component {
    constructor(props) {
        super(props);
        this.state = {foo: "bar"};
    }
}

Sample.defaultProps = {
    return {sampleProp: 0};
};
render

React组件可以忽略其他所有函数都不实现,但是一定要实现render函数,因为所有React组件的父类React.Component类对除render之外的生命周期函数都有默认实现。render函数并不做实际的渲染动作,它只负责返回一个JSX描述的结构,最终由React来操作渲染过程。

render函数应该是一个纯函数,完全根据this.state和this.props来决定返回的结果,而且不要产生任何副作用。在render函数中去调用this.setState是错误的,因为一个纯函数不应该引起状态的变化。

componentWillMount和componentDidMount

装载过程中,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

componentWillReceiveProps

当组件的props发生改变时会被调用。父组件的render被调用时,被渲染的子组件也会经历更新过程,不管父组件传给子组件的props有没有改变,都会触发子组件的componentWillReceiveProps。

我们在Counter组件类里增加这个函数定义,并在console输出一些文字:

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

在ControlPanel组件的render函数中,也做如下修改:

render() {
    console.log("enter ControlPanel render");
    return (
      
...
); }

除了在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(nextProps, nextState)

shouldComponentUpdate函数返回一个布尔值,告诉React库这个组件在这次更新过程中是否要继续。返回false会停止更新过程,就此结束,也不会引发后续的渲染了。

这个函数能够大大提升React组件的性能,不管React的组件渲染有多快,如果发现没有必要重新渲染,就干脆不要渲染。

修改Counter组件类增加shouldComponentUpdate函数的定义:

shouldComponentUpdate(nextProps, nextState) {
    return (nextProps.caption !== this.props.caption) ||
       (nextState.count !== this.state.count);
}
componentWillUpdate和componentDidUpdate

如果组件的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和state
React系列---之React(三)组件的生命周期

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/83673.html

相关文章

  • 《深入react技术栈》学习笔记(二)初入React世界

    摘要:用于规范的类型与必需的状态。表示由组件更改的数据,通常是通过与用户的交互来更改的。为了实现的修改,需要注册事件处理程序到相应的元素上。当事件发生时,将更新后的值是从中检索,并通知组件。通常情况下,该函数初始化状态使用,,或其他数据存储。 前言 上一篇文章中,我们讲到了JSX的一些用法和注意事项,这次我们来讲react中最基础也是特别重要的内容:组件。这篇文章包含组件的以下内容:状态、属...

    MRZYD 评论0 收藏0
  • React系列---React(一)初识React

    摘要:系列一初识系列二组件的和系列三组件的生命周期是推出的一个库,它的口号就是用来创建用户界面的库,所以它只是和用户界面打交道,可以把它看成中的视图层。系列一初识系列二组件的和系列三组件的生命周期 React系列---React(一)初识ReactReact系列---React(二)组件的prop和stateReact系列---React(三)组件的生命周期 showImg(https://...

    lanffy 评论0 收藏0
  • React 深入系列4:组件生命周期

    摘要:因为是深入系列文章,本文不会仔细介绍每个生命周期方法的使用,而是会重点讲解在使用组件生命周期时,经常遇到的疑问和错误使用方式。父组件发生更新导致的组件更新,生命周期方法的调用情况同上所述。 文:徐超,《React进阶之路》作者授权发布,转载请注明作者及出处 React 深入系列4:组件的生命周期 React 深入系列,深入讲解了React中的重点概念、特性和模式等,旨在帮助大家加深...

    warnerwu 评论0 收藏0
  • React 深入系列4:组件生命周期

    摘要:因为是深入系列文章,本文不会仔细介绍每个生命周期方法的使用,而是会重点讲解在使用组件生命周期时,经常遇到的疑问和错误使用方式。父组件发生更新导致的组件更新,生命周期方法的调用情况同上所述。 React 深入系列,深入讲解了React中的重点概念、特性和模式等,旨在帮助大家加深对React的理解,以及在项目中更加灵活地使用React。 组件是构建React应用的基本单位,组件需要具备数据...

    alexnevsky 评论0 收藏0
  • React系列---React(二)组件prop和state

    摘要:给赋值也是构造函数的工作之一。在的构造函数中,还给两个成员函数绑定了当前的执行环境,因为方式创建的组件并不自动给我们绑定到当前实例对象。我们可以利用的功能,避免判断逻辑这种充斥在构造函数之中,让代码更优。 React系列---React(一)初识ReactReact系列---React(二)组件的prop和stateReact系列---React(三)组件的生命周期 组件是React...

    Labradors 评论0 收藏0

发表评论

0条评论

geekzhou

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<