React 进修之路(2)
生命周期
React中的组件被看成是一个有生命的个体,因此赋予了声明周期的概念,就是为了定义组件所处的状态
React中组件共分三大周期,11个阶段
创建期(少年,成长)组件创建时候进入的时期
getDefaultProps getInitialState componentWillDid render componentDidMount
存在期(中年,反反复复的工作)组件内部数据(属性或者状态)更新时候进入的时期
componentWillReceiverProps shouldComponentUpdate componentWillUpdate render componentDidUpdate
销毁期(老年,消亡)组件从页面中删除时候进入的时期
componentWillUnmount
下面我们来一一细说每个时期
创建期
创建期是组件创建时候进入的时期,共分成五大阶段
一旦组件创建完成,创建期就结束,就进入下个周期 --> 存在期
1 创建默认属性数据 --> getDefaultProps
没有参数
作用域是构造函数,说明组件构造函数还没有执行完毕,所以不能访问组件实例化对象
访问不了组件中任何的数据,方法
返回值是默认的属性数据
2 初始化状态数据 --> getInitialState
没有参数
作用域是组件实例化对象
所以在这个方法中,可以访问属性数据了,但是不能访问状态数据
所以工作中,我们通常在这个方法中用属性的数据,初始化状态数据
这样就实现了将外部的数据,传递给内部更新维护
返回值是初始化的状态数据
3 组件即将被创建 --> componentWillMount
没有参数
作用域是组件实例化对象
在这个阶段,我们可以获取属性数据,可以获取状态数据,就是不能获取dom元素
所以工作中通常会简单处理属性数据,或者状态数据,或者处理内部的方法,但是绝对不能更新属性数据或者状态数据,也不要为组件绑定元素绑定事件
4 渲染输出组件 --> render
没有参数
作用域是组件实例化对象
不能获取dom元素(这个方法执行完毕才能获取),可以获取属性数据,可以获取状态数据
返回值是渲染输出的虚拟dom元素
5 组件创建完成 --> componentDidMount
没有参数
作用域是组件实例化对象
工作中很常用
可以访问属性数据,可以访问状态数据,可以访问dom元素
还可以在这里发送异步请求,请求数据更新状态
还可以绑定事件
还可以更新状态
这个方法执行完毕就标志着组件创建期的结束
获取组件对应的真实dom元素
0.13版本之前
this.getDOMNode()
React.findDOMNode(this)
都可以获取
0.13版本之后
只能使用ReactDOM.findDOMNode(this)
1var GoTop = React.createClass({ 2 // 第一个阶段 初始化默认属性 3 getDefaultProps: function () { 4 console.log(111, this) 5 console.log(111, arguments) 6 return { 7 text: '分类网址' 8 } 9 }, 10 // 第二个阶段 初始化状态 11 getInitialState: function () { 12 console.log(222, this) 13 console.log(222, arguments) 14 // console.log(this.state) 15 return { 16 color: 'red', 17 // 用属性数据更新状态 18 text: this.props.text 19 } 20 }, 21 // 第三个阶段 组件即将构建 22 componentWillMount: function () { 23 console.log(333, this) 24 console.log(333, arguments) 25 // 获取虚拟dom对应的真实的dom元素 26 // console.log(ReactDOM.findDOMNode(this)) 27 // console.log(this.props) 28 // console.log(this.state) 29 }, 30 // 第四个阶段 渲染组件 31 render: function () { 32 console.log(444, this) 33 console.log(444, arguments) 34 // console.log(ReactDOM.findDOMNode(this)) 35 // 渲染输出虚拟dom 36 return ( 37 <div className="go-top"> 38 {/*这里的文案实时改变,需要在内部围护,因此要使用状态数据*/} 39 <span onClick={this.goTop}>{this.state.text}</span> 40 </div> 41 ) 42 }, 43 // 返回顶部的方法 44 goTop: function () { 45 if (this.state.text === '返回顶部') { 46 window.scrollTo(0, 0) 47 } 48 }, 49 // 第五个阶段 组件构建完成 50 componentDidMount: function () { 51 console.log(555, this) 52 console.log(555, arguments) 53 // 获取虚拟dom对应的真实的dom元素 54 // console.log(ReactDOM.findDOMNode(this)) 55 // react以及组件实例化对象上的不建议使用了 56 // console.log(React.findDOMNode(this)) 57 // console.log(this.getDOMNode()) 58 59 // 事件在最后一个阶段绑定 60 window.onscroll = function () { 61 // console.log(111) 62 // 滚动200更改文案 63 if (window.scrollY > 200) { 64 this.setState({ 65 text: '返回顶部' 66 }) 67 } else { 68 this.setState({ 69 text: '分类网址' 70 }) 71 } 72 }.bind(this) 73 } })
在说下一个生命周期之前,插入一个小知识点
子组件
在组件中使用的组件,叫该组件的子组件,在组件中使用子组件很简单,跟使用虚拟DOM元素一模一样
<Slider> <GoTop color=“red” /> </Slider>
这里定义的GoTop组件就叫Slider组件的子组件
在组件中可以为子组件添加属性,添加的属性就是对子组件传递的数据
传递的数据分成四类
1 如果属性值是一个变量(字符串,对象等)
传递给子组件的数据不会改变
2 如果属性值是父组件中的属性数据
传递给子组件中的数据往往不会改变(除非父组件也是一个子组件)(因为组件的属性数据只能在外部改变,如果父组件是其他组件的子组件,父组件的属性数据可能会改变,此时传递给子组件的数 据就可能发生改变)
3 如果属性值是父组件中的状态数据
如果父组件中状态数据发生了改变,那么传递给子组件的数据就发生了改变
4 如果属性值是父组件中的方法
父组件提供的方法作为子组件的事件回调函数,作用域仍然是父组件
回调函数两个参数
第一个是react封装的事件对象
第二个是源生的事件对象
如果父组件提供的方法在子组件的方法内执行,没有参数了,但作用域依旧是父组件
(搞不清楚的童鞋们请注意观察下列代码的第26行和29行)
这里的数据传递,父组件将数据传递给子组件,本质上就是父组件向子组件通信
1 // 创建GoTop组件 2 var GoTop = React.createClass({ 3 // 定义默认状态数据 4 getDefaultProps: function () { 5 return { 6 text: '网址导航' 7 } 8 }, 9 // 定义初始化状态 10 getInitialState: function () { 11 return { 12 // 用属性数据赋值状态数据 13 text: this.props.text 14 } 15 }, 16 // 返回顶部的方法 17 goTop: function () { 18 // console.log(111,arguments) 19 // console.log(222,this); 20 // 在子组件的方法中使用父组件提供的方法 21 this.props.goBackByParent() 22 }, 23 render: function () { 24 console.log(this) 25 // 渲染输出虚拟DOM 26 // <span onClick={this.props.goBackByParent}>{this.props.text}</span> 27 return ( 28 <div className="go-top"> 29 <span onClick={this.goTop}>{this.props.text}</span> 30 </div> 31 ) 32 } 33 }) 34 35 // 定义slider组件 36 var Slider = React.createClass({ 37 // 定义属性 38 getDefaultProps: function () { 39 return { 40 title: '头条新闻' 41 } 42 }, 43 // 定义状态数据 44 getInitialState: function () { 45 return { 46 text: '新闻头条' 47 } 48 }, 49 // 渲染输出虚拟dom 50 render: function () { 51 return ( 52 <div className="slider"> 53 {/*GoTop 就是Slider的子组件*/} 54 <GoTop color="red" title={this.props.title} text={this.state.text} goBackByParent={this.goBack} /> 55 </div> 56 ) 57 }, 58 // 定义返回顶部方法 59 goBack: function () { 60 console.log(123, this, arguments) 61 }, 62 // 定义滚动事件 63 componentDidMount: function () { 64 window.onscroll = function () { 65 if (window.scrollY > 200) { 66 this.setState({ 67 text: '返回顶部' 68 }) 69 } else { 70 this.setState({ 71 text: '网址导航' 72 }) 73 } 74 }.bind(this) 75 } 76 }) 77 78 // 将组件渲染到页面中 79 ReactDOM.render(<Slider />, document.getElementById('app'))
存在期
存在期也有五个阶段
这五个阶段方法的作用域都是组件实例化对象,因此这个五个阶段都能访问组件中的属性和状态,当然还有虚拟DOM
6 组件即将接收新的属性 --> componentWillReceiveProps
有一个参数表示新的属性对象
工作中经常在这个阶段用新的属性对象,更新状态数据
这个方法只有在属性更新的时候,会执行,状态更新的时候不会执行
7 组件是否应该更新 --> shouldComponentUpdate
有两个参数
第一个参数表示新的属性
第二个参数表示新的状态
通过作用域可以访问原来的属性,原来的状态,原来的dom
必须有返回值
True表示可以继续更新
False表示不能继续更新
我们可以通过设置false属性来优化组件更新的频率
8 组件即将更新 --> componentWillUpdate
有两个参数
第一个参数表示新的属性
第二个参数表示新的状态
通过作用域可以访问原来的属性,原来的状态,原来的dom
在这个阶段,一定不要再更新属性或者状态了
属性或者状态数据,在这个阶段更新完毕的
9 组件即将渲染输出新的虚拟DOM --> Render(这里的render方法跟创建期是同一个)
通过作用域可以访问新的的属性,新的的状态,原来的dom
在这里绝对不能操作原来的dom,因为在创建期也使用这个方法(在创建期的render方法中是不能访问dom的)
10 组件更新完毕 --> componentDidUpdate
有两个参数
第一个表示原来的属性对象
第二个表示原来的状态对象
是最后一次可以访问到原来的属性数据或者状态数据了
通过作用域可以访问新的的属性,新的的状态,新来的dom
这个方法执行完毕,组件存在期就完成一次更新,我们可以在这个方法中再次更新属性,再次更新状态,发送请求,绑定事件等等
当组件中属性数据或者状态数据发生了改变的时候,会进入该周期
1 // 创建GoTop组件 2 var GoTop = React.createClass({ 3 // 定义默认状态数据 4 getDefaultProps: function () { 5 return { 6 text: '网址导航' 7 } 8 }, 9 // 定义初始化状态 10 getInitialState: function () { 11 return { 12 // 用属性数据赋值状态数据 13 text: this.props.text 14 } 15 }, 16 // 返回顶部的方法 17 goTop: function () { 18 console.log(111) 19 }, 20 render: function () { 21 console.log(4, this.state.text) 22 console.log(4, arguments) 23 // 渲染输出虚拟DOM 24 return ( 25 <div className="go-top"> 26 <span onClick={this.props.goBackByParent}>{this.state.text}</span> 27 </div> 28 ) 29 }, 30 // 更新状态 31 componentDidMount: function () { 32 // var me = this; 33 // setTimeout(function () { 34 // me.setState({ 35 // text: '返回顶部' 36 // }) 37 // }, 1000) 38 window.onscroll = function () { 39 // console.log(111) 40 // 滚动200更改文案 41 if (window.scrollY > 200) { 42 this.setState({ 43 text: '返回顶部' 44 }) 45 } else { 46 this.setState({ 47 text: '分类网址' 48 }) 49 } 50 }.bind(this) 51 }, 52 // 第一个阶段是 组件即将接收新的属性 53 componentWillReceiveProps: function(newProps) { 54 console.log(1, this) 55 console.log(1, arguments) 56 // 用属性数据更新状态 57 this.setState({ 58 text: newProps.text 59 }) 60 }, 61 // 第二个阶段 组件是否应该更新 62 shouldComponentUpdate: function (newProps, newState) { 63 console.log(2, this) 64 console.log(2, arguments) 65 console.log(ReactDOM.findDOMNode(this).innerHTML) 66 // 组件状态text值更新时候,进入存在期, 67 // 判断新的text值与旧的text值的变化 68 if (newState.text !== this.state.text) { 69 return true; 70 } else { 71 return false 72 } 73 // return false 74 }, 75 // 第三个阶段 组件即将更新 76 componentWillUpdate: function() { 77 console.log(3, this.state.text) 78 console.log(3, arguments) 79 }, 80 // 第五个阶段 组件更新完毕 81 componentDidUpdate: function() { 82 console.log(5, this) 83 console.log(5, arguments) 84 console.log(ReactDOM.findDOMNode(this).innerHTML) 85 86 } 87 }) 88 89 // 定义slider组件 90 var Slider = React.createClass({ 91 // 定义属性 92 getDefaultProps: function () { 93 return { 94 title: '头条新闻' 95 } 96 }, 97 // 定义状态数据 98 getInitialState: function () { 99 return { 100 text: '新闻头条' 101 } 102 }, 103 // 渲染输出虚拟dom 104 render: function () { 105 return ( 106 <div className="slider"> 107 {/*GoTop 就是Slider的子组件*/} 108 <GoTop color="red" title={this.props.title} text={this.state.text} goBackByParent={this.goBack} /> 109 </div> 110 ) 111 }, 112 // 定义返回顶部方法 113 goBack: function () { 114 console.log(123, this, arguments) 115 }, 116 // 定义滚动事件 117 componentDidMount: function () { 118 119 } 120 }) 121 122 // 将组件渲染到页面中 123 ReactDOM.render(<Slider />, document.getElementById('app'))
销毁期
销毁期:当组件从页面中删除,组件就进入了销毁期
11 销毁期只有一个阶段 --> componentWillUnmount
没有参数
作用域是组件实例化对象
这个方法是能够访问组件的最后一次机会了,这个方法执行完毕之后,组件就销毁了
1 // 定义返回顶部组件 2 var GoBack = React.createClass({ 3 render: function () { 4 return ( 5 <div className="go-back"> 6 <span>返回顶部</span> 7 </div> 8 ) 9 }, 10 // 定义组件销毁期的阶段 11 componentWillUnmount: function () { 12 console.log(this) 13 console.log(arguments) 14 } 15 }) 16 17 // 将组件渲染到页面中 18 ReactDOM.render(<GoBack />, document.getElementById('app')) 19 20 // 3秒钟之后渲染h1 21 setTimeout(function () { 22 ReactDOM.render(<h1>啦啦啦,我是文字</h1>, document.getElementById('app')) 23 }, 3000)