react初始化阶段
- 初始化阶段可以使用的函数:
getDefaultProps:只调用一次,实例之间共享引用。只有在组件的第一个实例被初始化的时候,才会调用他,然后react会把这个函数的返回结果保存起来,从第二个实例开始,他们的默认属性都是这同一个结果。实例之间共享引用,在js中有两种类型的数据,一种值类型,比如字符串,布尔值等,一种是引用类型,比如数组,对象等,如果函数返回的是引用类型的数据,那么react会把引用保存起来,在创建不同的实例的时候,他会使用同一个引用当做属性,但是我们知道,引用指向的都是同一个地址,所以说不同实例之间操作的其实是同一个数据,所以在用这个函数的时候,要注意返回的是引用还是值。
getInitialState:初始化每个实例特有的状态。从这个函数开始,每个实例被初始化的时候,都会调用他, 不像第一个函数只会调用一次,第一个函数处理的是属性,第二个函数处理的是状态,由于状态是每个实例自己内部的信息,每个实例要维护自己状态,所以不同的实例有不同的状态,那么都需要调用这个函数。
componentWillMount:render之前最后一次修改状态的机会。在这个时候,你还是可以修改状态的,但是在render里面就不可以在修改状态了。
render:只能访问this.props和this.state,只有一个顶层组件,不允许修改状态和dom输出。this.props和this.state是render特有的两个数据源,除此以外,你不应该在获取其他的数据信息。只有一个顶层组件?render的返回值只能是一个组件,这个组件可以包含很多的子组件,也可以包含很多的子代码,但是本质上他还是一个组件,你不能返回一个数组。不允许修改状态和dom输出。如果一定要修改,也是可以的,但是react不推荐这么做,如果你修改了状态和输出的话,那么render函数就无法再服务端进行使用,当然我们大部分时候是在客户端使用的render函数,如果你想提高网站的加载性能,就可以在服务端进行处理,但是你的render函数需要修改状态和dom输出,在服务端得时候是没有这样的环境的,所以你如果修改了状态和输出,就只能在浏览器使用了,这回大大的限制你的系统性能。第二个原因就是你如果在render里面修改了状态和输出,会导致代码的逻辑变得非常的复杂,很难经过状态分析出结果,react设计目的之一就是让组件的逻辑变得清晰简单,这样就违背了这样的目的。你自己还是别人就很难看懂这段代码。
componentDidMount:成功render并渲染完成真实dom之后触发,可以修改dom。这个函数被调用的时候,dom已经被创建。 - 实例:查看触发顺序。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.min.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> var style={ color:"red", border:"1px solid #f99", width:"200px", height:"50px" }; var HelloWorld=React.createClass({ getDefaultProps: function(){ console.log("getDefaultProps,1") }, getInitialState: function(){ console.log("getInitialState,2"); return null; }, componentWillMount: function(){ console.log("componentWillMount,3") }, render: function(){ console.log("render,4") return <p ref="childp">hello,{( function(obj){ if(obj.props.name) return obj.props.name else return "world" } )(this)}</p> }, componentDidMount:function(){ console.log("componentDidMount,5"); }, }); React.render(<div style={style}>HelloWorld</div>,document.body) </script> </body> </html>
注意上面代码中红色的标记部分,我们只是输出的字符串HelloWorld,并不是标签<HelloWorld></Helloworld>,所以此时的控制台和输出是这样。
我们可以看出,getDefaultProps在实际的使用中,是直接调用的,也就是在React.createClass之后,就会被调用并把结果存储起来,及时你没有生成实例,这个函数也会被调用,react这么做主要目的就是为了提高性能,尽可能早的将我们要做的事情处理好,这样当我们要使用HelloWorld实例的时候,就会省掉调用这个函数的时间从而提高性能。我们改一下代码,让其正确输出。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.min.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> var style={ color:"red", border:"1px solid #f99", width:"200px", height:"50px" }; var HelloWorld=React.createClass({ getDefaultProps: function(){ console.log("getDefaultProps,1") }, getInitialState: function(){ console.log("getInitialState,2"); return null; }, componentWillMount: function(){ console.log("componentWillMount,3") }, render: function(){ console.log("render,4") return <p ref="childp">hello,{( function(obj){ if(obj.props.name) return obj.props.name else return "world" } )(this)}</p> }, componentDidMount:function(){ console.log("componentDidMount,5"); }, }); React.render(<div style={style}><HelloWorld></HelloWorld></div>,document.body) </script> </body> </html>
- 各个实例的正确用法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/jquery/2.0.3/jquery.min.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.min.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> $(document).ready( function(){ var count=0; var style={ color:"red", border:"1px solid #090", }; var HelloWorld=React.createClass({ getDefaultProps:function(){ console.log("getDefaultProps,1"); return{name:"Tom"}; }, getInitialState:function(){ console.log("getInitialState,2"); return{ myCount:count++, ready:false }; }, componentWillMount:function(){ console.log("componentWillMount,3"); this.setState({ready:true}); }, render:function(){ console.log("render,4"); return <p ref="childp">Hello,{ this.props.name ? this.props.name : "World" }<br/>{""+this.state.ready}</p>; }, componentDidMount:function(){ console.log("componentDidMount,5"); //这里才可以操作dom $(React.findDOMNode(this)).append("surprise!"); }, //HelloWolrld内部 }); React.render(<div style={style}><HelloWorld></HelloWorld></div>,document.body) //function 内部 } //ready内部 ) </script> </body> </html>
- 输出count,生成多个HelloWorld
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/jquery/2.0.3/jquery.min.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.min.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> $(document).ready( function(){ var count=0; var style={ color:"red", border:"1px solid #090", }; var HelloWorld=React.createClass({ getDefaultProps:function(){ console.log("getDefaultProps,1"); return{name:"Tom"}; }, getInitialState:function(){ console.log("getInitialState,2"); return{ myCount:count++, ready:false }; }, componentWillMount:function(){ console.log("componentWillMount,3"); this.setState({ready:true}); }, render:function(){ console.log("render,4"); return <p ref="childp">Hello,{ this.props.name ? this.props.name : "World" }<br/>{""+this.state.ready}{this.state.myCount}</p>; }, componentDidMount:function(){ console.log("componentDidMount,5"); $(React.findDOMNode(this)).append("surprise!"); }, //HelloWolrld内部 }); React.render(<div style={style}><HelloWorld></HelloWorld><br/><HelloWorld></HelloWorld></div> ,document.body) //function 内部 } //ready内部 ) </script> </body> </html>