- 初始化階段可以使用的函數:
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>