可否理解一个组件的生命周期是很是重要的,甚至能够说是最重要的内容,他是一切进阶的基石,下面咱们就从angular1的生命周期开始吧。html
angular1的生命周期在1.5以前是很晦涩的,controller、compile、preLink、postLink,compile的return函数。从字面上让人彻底摸不着头脑,到了1.5增长了angular.component,这一问题有了很大改观,生命周期所有放到controller(controller再也不做为一个生命周期钩子存在),controller就是一个class,实例函数$onInit、$onPostLink和$onDestroy组成了新的生命周期钩子,从字面上也容易理解了不少。$onInit表明编译前,在这里你能够对$scope作属性变动,和逻辑定义;$onPostLink表明编译后,这个时候子指令已完成了编译,你能够在这里获取到任意子指令实例并调用其方法;$onDestroy在当前scope被销毁时调用,在这里你须要对dom作销毁,以及可能的全局变量作清空。很简单就是组件编译前、组件编译后和组件销毁时。那么咱们再看看react的生命周期钩子。react
react的生命周期分为三大阶段,git
- 插入dom(mount)
- 从新render(update)
- 销毁dom(unmount)
在定义class(组件)的时候其实就是在定义一个状态机,定义了各类状态的响应,这里包括这三大阶段的钩子以及事件响应,等待触发条件的知足。github
1 插入dom(mount)算法
先来讲下第一阶段,首次render触发时会执行如下钩子函数,redux
getDefaultProps: function(){
return { /* 默认属性 */};
}复制代码
getInitialState性能优化
getInitialState: function(){
return { /* 初始状态 */};
}复制代码
这两个函数不难理解,目的是使代码结构更清晰,不须要在constructor里作过多的打底处理。dom
componentWillMount
这个方法在出现class XX extends React.Component
以后其实就能够用constructor
来代替了。对于angular1.5这和$onInit
也是相似的,一样也能够用constructor代替。异步
render
这个函数其实和angular指令中的template属性(值对应一个函数)很类似,可是借助jsx,render比template属性强大实在太多,angular所提供的template不够灵活,在template函数中没法拿到$scope,天然咱们就选择例如ngIf
这样的属性指令来作模版输出控制,该指令会在当前指令做用域下再建立一个子做用域,这使得咱们在获取子组件的实例的时候会比较麻烦,ngRepeat
、ngSwitch
都是这样,angular1的初衷是不但愿咱们本身作字符串拼接,的确就算咱们能拿到$scope,字符串拼接也实在不够优雅。
因此render函数直白点完成了两件事情:函数
全部叶子组件的jsx模版都是由基础原生html标签、属性以及react所提供的代理属性组成的,所以若是你写以下一段模版代码:
render(){
return (
<div num=1 changehandler={this.changeHandler.bind(this)}/> ) }复制代码
num
和changehandler
属性会直接被忽略,若是你想在原生标签上使用自定义属性,请在属性前面添加data-
。
componentDidMount
componentDidMount
和angular中的link或postLink很类似,可是它更让人放心,由于angular中若是你想在link中获取带有ngIf或ngRepeat的dom是获取不到的(由于会再transclude一次并等待下次脏数据校验才会插入dom,有兴趣的同窗能够移步重复transclude和ngIf脏数据校验),所以在这里你能够放心的访问dom。
小结:上述方法除了render
,只会伴随第一次render执行一次。
2 从新render
当组件props和state(经过setState)发生变动时,会触发re-render
操做。所以这里咱们把state和props变化分开来讲。
在angular1中其实并无屡次触发的钩子,像前面说到的controller、compile等也都只执行一次,其实react的从新渲染在angular相似$watch,通常咱们在$watch来实现dom的变动,这种命令式的修改dom固然是不推荐的,react采用了一种更完全的方式,给人的感觉就像又走了一遍第一次渲染同样,而你能够这样理解,相对于第一次,它可能仅仅变动了个别state或props,经过虚拟dom和diff算法,react帮助你高效的将变动应用于虚拟dom上最终re-render出新的dom树。
2.1 state变动
状态变动会触发如下几个钩子
shouldComponentUpdate: function(nextProps, nextState){
return true
}复制代码
该函数给用户一个机会使得其能够控制是否须要进行从新渲染,angular1并无提供终止指令编译的钩子函数,这是react的高级特性了,主要针对性能优化,本身没有用过就不误导你们了。componentWillUpdate
componentWillUpdate: function(nextProps, nextState){
// 为re-render作准备
}复制代码
为啥须要这个钩子呢,由于只有shouldComponentUpdate
返回true才能肯定必定会从新渲染,那么在这里咱们能够对界面的提示UI作变动,好比以前为了获取state或props会由于异步请求出现loading,那么这个时候就能够隐藏loading。记住这里不能有任何会再次触发组件从新渲染的逻辑。
componentDidUpdate
componentDidUpdate: function(prevProps, prevState){
// 能够访问渲染完成的dom
}复制代码
这个没啥可说的,和componentDidMount
是同样的。
2.2 props变动
componentWillReceiveProps: function(nextProps) {
this.setState({
// new state
});
}复制代码
不像state须要调用setState才会触发re-render,由父组件致使的任何属性变动都会触发re-render,不须要调用额外的方法。其实props变动所经历的生命周期钩子和state几乎同样,惟一不一样是在shouldComponentUpdate以前增长了componentWillReceiveProps,用意也十分明显,咱们能够在componentWillReceiveProps中经过setState对state作修改,好比组件内部的state是根据某个或多个props计算得出的,这样咱们在调用setState时候也不会形成额外的re-render被触发,深刻理解react
3 销毁dom(unmount)
当咱们改变UI布局或者使用接口删除组件树上某个组件时就会触发组件的componentWillUnmount
方法,在这里你能够取消事件监听或定时器,以及其余会形成全局引用的变量。
class App extend Component {
componentWillUnmount(){
// unregister event or clear timer
}
}
render(<App />, document.getElementById('root') function ummount(){ React.unmountComponentAtNode(document.getElementById('root')); }复制代码
4 结束
这篇其实和angular1的对比不是太多,但其实大概的生命周期和angular1仍是大同小异,特别是re-render这块更有条理也更有性能优点。react与angular1的对比先暂告一段落,后面将开始redux的学习,同时会对官方的demo作详细讲解。
文中若有错误请你们及时纠正,谢谢。