React Native 组件生命周期 ----ES6

在React Native中使用组件来封装界面模块时,整个界面就是一个大的组件,开发过程就是不断优化和拆分界面组件、构造整个组件树的过程。

所以学习理解组件的生命周期显得尤为重要!

一、组件的属性(props)和状态(state)

1. 属性(props)

它是组件的不可变属性(组件自己不可以自己修改props,只可由其他组件调用它时在外部改变)。

组件自身定义了一组props作为对外提供的接口,展示一个组件时只需要指定props作为节点的属性。

一般组件很少需要对外公开方法(例外:工具类的静态方法等),唯一的交互途径就是props。所以说它也是父组件与子组件通信的桥梁

组件自己不可以自己修改props(即:props可认为是只读的),只可由其他组件调用它时在外部修改。

2. 状态(state)

它是组件的内部状态属性,主要用来存储组件自身需要的数据。

除了初始化时可能由props来决定,之后就完全由组件自身去维护。

组件中由系统定义了setState方法,每次调用setState时都会更新组件的状态,触发render方法重新渲染界面

需要注意的是render方法是被异步调用的,这可以保证同步的多个setState方法只会触发一次render,这样做是有利于提高性能的。

二、组件的生命周期

对于自定义组件,除了必须实现的render方法,还有一些其他的可选方法可被调用。这些方法会在组件的不同时期之行,所以也可以说这些方法是组件的生命周期方法。

对于组件的生命周期来说一般分为四个阶段,分别为:

创建阶段、实例化阶段、运行(更新)阶段、销毁阶段。

1. 创建阶段

该阶段主要发生在创建组件类的时候,在这个阶段中会初始化组件的属性类型和默认属性。

defaultProps / getDefaultProps()

这里会初始化一些默认的属性,通常会将固定的内容放在这个过程中进行初始化和赋值,一个控件可以利用this.props获取在这里初始化它的属性,由于组件初始化后,再次使用该组件不会调用getDefaultProps函数,所以组件自己不可以自己修改props(即:props可认为是只读的),只可由其他组件调用它时在外部修改。

在ES5里,属性类型和默认属性分别通过propTypes成员和getDefaultProps方法来实现。

//ES5

propTypes: {

autoPlay: React.PropTypes.bool.isRequired,

maxLoops: React.PropTypes.number.isRequired,

posterFrameSrc: React.PropTypes.string.isRequired,

videoSrc: React.PropTypes.string.isRequired,

},

getDefaultProps: function() {        

               return {          

                                autoPlay: false,            

                                 maxLoops: 10,       

                           };

},

在ES6里,可以统一使用static成员来实现.

//ES6

static propTypes = {//用来指定props的类型

                                autoPlay: React.PropTypes.bool.isRequired,

                                 maxLoops: React.PropTypes.number.isRequired,

                                 posterFrameSrc: React.PropTypes.string.isRequired,

                                videoSrc: React.PropTypes.string.isRequired,

};  // 注意这里有分号

static defaultProps = {

                          autoPlay: false,

                           maxLoops: 10,

};  // 注意这里有分号

2. 实例化阶段

该阶段主要发生在组件类被调用(实例化)的时候。

组件类被实例化的时候,触发一系列流程:

1) constructor(props) / getInitialState()

这里是对控件的一些状态进行初始化,由于该函数不同于getDefaultProps,在以后的过程中,会再次调用,所以可以将控制控件的状态的一些变量放在这里初始化,如控件上显示的文字,可以通过this.state来获取值,通过this.setState来修改state值。

在ES5里,通过getInitialState对状态进行初始化

getInitialState: function() {

                    return {

                              loopsRemaining: this.props.maxLoops,

                                 };

},

在ES6里,通过constructor(构造器)对状态进行初始化

constructor(props){

        super(props);

        this.state = {

                 loopsRemaining: this.props.maxLoops,

                            };

    }

2) componentWillMount()

准备加载组件。

这个调用时机是在组件创建,并初始化了状态之后,在第一次绘制 render() 之前。可以在这里做一些业务初始化操作,也可以设置组件状态。这个函数在整个生命周期中只被调用一次。

如果在这个函数里面调用setState,本次的render函数可以看到更新后的state,并且只渲染一次。

3) render()

render是一个组件必须有的方法,形式为一个函数,渲染界面,并返回JSX或其他组件来构成DOM,和Android的XML布局、WPF的XAML布局类似,只能返回一个顶级元素

4) componentDidUpdate()

调用了render方法后,组件加载成功并被成功渲染出来以后所执行的hook函数,一般会将网络请求等加载数据的操作,放在这个函数里进行,来保证不会出现UI上的错误

3. 运行(更新)阶段

该阶段主要发生在用户操作之后,或者父组件有更新的时候,此时会根据用户的操作行为,进行相应的界面结构调整。

触发的流程如下:

1) componentWillReceiveProps(nextProps)

当组件接收到新的props时,会触发该函数。在该函数中,通常可以调用setState()来完成对state的修改

输入参数 nextProps 是即将被设置的属性,旧的属性还是可以通过 this.props 来获取。在这个回调函数里面,你可以根据属性的变化,通过调用 this.setState() 来更新你的组件状态,这里调用更新状态是安全的,并不会触发额外的 render() 调用。如下:

componentWillReceiveProps: function(nextProps) {

               this.setState({

                        likesIncreasing: nextProps.likeCount > this.props.likeCount

                  });

}

2) shouldComponentUpdate(nextProps, nextState)

返回布尔值(决定是否需要更新组件)

输入参数 nextProps 和上面的 componentWillReceiveProps 函数一样,nextState 表示组件即将更新的状态值。这个函数的返回值决定是否需要更新组件,如果 true 表示需要更新,继续走后面的更新流程。否者,则不更新,直接进入等待状态。

默认情况下,这个函数永远返回 true 用来保证数据变化的时候 UI 能够同步更新。在大型项目中,你可以自己重载这个函数,通过检查变化前后属性和状态,来决定 UI 是否需要更新,能有效提高应用性能。

3) componentWillUpdate(nextProps, nextState)

shouldComponentUpdate返回true或者调用forceUpdate之后,就会开始准更新组件,并调用 componentWillUpdate()。

输入参数与 shouldComponentUpdate 一样,在这个回调中,可以做一些在更新界面之前要做的事情。需要特别注意的是,在这个函数里面,你就不能使用 this.setState 来修改状态。这个函数调用之后,就会把 nextProps 和 nextState 分别设置到 this.props 和 this.state 中。紧接着这个函数,就会调用 render() 来更新界面了。

4) render()

再确定需要更新组件时,调用render,根据diff算法,渲染界面,生成需要更新的虚拟DOM数据。

5) componentDidUpdate()

虚拟DOM同步到DOM中后,执行该方法,可以在这个方法中做DOM操作。

除了首次render之后调用componentDidMount,其它render结束之后都是调用componentDidUpdate。

componentWillMount、componentDidMount和componentWillUpdate、componentDidUpdate可以对应起来。区别在于,前者只有在挂载的时候会被调用;而后者在以后的每次更新渲染之后都会被调用。

ps:绝对不要在componentWillUpdate和componentDidUpdate中调用this.setState方法,否则将导致无限循环调用。

4. 销毁阶段

该阶段主要发生组件销亡的时候,触发componentWillUnmount。当组件需要从DOM中移除的时候,通常需要做一些取消事件绑定,移除虚拟DOM中对应的组件数据结构,销毁一些无效的定时器等工作,都可以在这个方法中处理。

componentWillUnmount()

当组件要被从界面上移除的时候,就会调用 componentWillUnmount。

在这个函数中,可以做一些组件相关的清理工作,例如取消计时器、网络请求等

三、组件更新的方式(更新阶段详细)

本来是没有想要要详细写这部分内容的,不过看到另一篇文章,写得好好,就也放进来详细讲下,感谢原文作者

参考自:http://www.jianshu.com/p/4784216b8194里的更新方式部分

更新组件(重新渲染界面)的方式有以下四种

首次渲染Initial Render,即首次加载组件

调用this.setState,状态发生改变(并不是一次setState会触发一次render,React可能会合并操作,再一次性进行render)

父组件发生更新(一般就是props发生改变,但是就算props没有改变或者父子组件之间没有数据交换也会触发render)

调用this.forceUpdate,强制更新

用图来表示这四种方式如下:


四、总结

1. 组件生命周期总体流程图


2. 生命周期的回调函数总结

生命周期                                                            调用次数                               能否使用 setSate()

defaultProps / getDefaultProps                          1                                                 (全局调用一次)

constructor / getInitialState                                1                                                    否

componentWillMount                                          1                                                     

render                                                                    >=1                                                否

componentDidMount                                         1                                                       

componentWillReceiveProps                             >=0                                                 

shouldComponentUpdate                                  >=0                                                 否

componentWillUpdate                                        >=0                                                 否

componentDidUpdate                                         >=0                                                 否

componentWillUnmount                                      1                                                       否

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容