- 屬性的含義和用法
props=properties 英文中屬性的意思。屬性不可以修改,也就是屬性不可以由組件進行修改,組件的屬性是由父組件傳遞過來的,相當於組件在出生的時候帶的。
用法
第一種:直接在調用組件的時候傳入一個鍵值對,
這個鍵值對可以是字符串:
<HelloWorld name="李明"></HelloWorld>
可以是大括號:大括號本質上是一個js的求值表達式,里面可以寫很多內容,最簡單的就是寫數據,直接拿到的數字
<HelloWorld name={123}></HelloWorld>
可以是大括號,里面是字符串:他的值就是里面的字符串,當然在實例的使用中,我們直接入第一個一樣使用。
<HelloWorld name={"Tim"}></HelloWorld>
可以是一個數組:這樣屬性拿到的也是一個數組,在編寫多選框和表單的時候用的多看,組件可以根據傳入的屬性來構建子組件
<HelloWorld name={[1,2,3]}></HelloWorld>
可以直接傳入一個變量:這個變量可以在外部定義,然后在組件里面去引用他。變量可以是一個數組,對象,字符串,數值都可以,
<HelloWorld name={variable}></HelloWorld>
可以是函數求值表達式:就是直接定義一個函數並調用他,一個的形式就是兩個括號放在一起,這樣我們就可以定義一個匿名函數並調用他,大括號的值就是匿名函數的返回值.
第二種:可以理解為展開,我們使用這三個點,就可以直接把里面的值拿出來,可以拿到兩個屬性,如果把三個點去掉,HelloWorld拿到的就是一個props對象,還得自己展開。var props={ one:"123", two:321, } <HelloWorld {...props} />
這個props有兩個屬性,一個one,一個two,如果我們使用第一種鍵值對的方式,就得寫兩個,這樣寫起來比較繁瑣,而且我們如果修改props,就得修改下面的屬性引用。代碼的可維護性不高,而且動態性不高。
var props={ one:"123", two:321, } <HelloWorld one={props.one} two={props.two} />
instance.setProps({name:"Tom"})
- 實例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>hello world</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.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 #f09", }; var HelloWorld=React.createClass({ render: function(){ return <p>Hello,{this.props.name ? this.props.name : "world"}</p> }, }); var HelloUniverse=React.createClass({ getInitialState:function(){ return {name:''}; }, handleChange:function(event){ this.setState({name:event.target.value}); }, render:function(){ return <div> <HelloWorld name={this.state.name}></HelloWorld> <br/> <input type="text" onChange={this.handleChange} /> </div> }, }); React.render(<div style={style}><HelloUniverse></HelloUniverse></div>,document.body); </script> </body> </html>
注意圖中的紅色標記區域,如果把div和return分開放在兩行就會報錯,如下
報錯:
Uncaught Error: Invariant Violation: HelloUniverse.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
修改代碼使用第二種賦值方式:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>hello world</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.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 #f09", }; var HelloWorld=React.createClass({ render: function(){ return <p>Hello,{this.props.name1+' '+this.props.name2}</p> }, }); var HelloUniverse=React.createClass({ getInitialState:function(){ return { name1:'tom', name2:'John', }; }, handleChange:function(event){ this.setState({name:event.target.value}); }, render:function(){ return <div> <HelloWorld {...this.state}></HelloWorld> <br/> <input type="text" onChange={this.handleChange} /> </div> }, }); React.render(<div style={style}><HelloUniverse></HelloUniverse></div>,document.body); </script> </body> </html>
第三種:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>hello world</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.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 #f09", }; var HelloWorld=React.createClass({ render: function(){ return <p>Hello,{this.props.name ? this.props.name : "world"}</p> }, }); var instance=React.render(<HelloWorld></HelloWorld>,document.body); //這里返回的是react的返回值,這里設置的是HelloWorld的屬性,並且render函數進行了更新 instance.setProps({name:'tom'}) </script> </body> </html>
- 狀態的含義和用法
狀態 state:使用this.state來引用,state本身就是狀態的意思,狀態指的是事物所處的狀況,狀況就是環境。注意:狀態是事物自己處理的,不和屬性一樣,屬性是天生的,事物一般來說沒有辦法修改。狀態是事物本身的是事物的私有屬性,也就是由自己決定,父組件和子組件都不能改變他。給定了狀態就一定知道結果是什么。
用法:
getInitialState:初始化每個實例特有的狀態
setState:更新組件狀態,原則上是經常使用的,但是setProps原則上面不推薦你使用,
setState會觸發的行為,他會調用diff算法。
實例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>hello world</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.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 #f09", }; var HelloWorld=React.createClass({ render: function(){ return <p>Hello,{this.props.name}</p> }, }); var HelloUniverse = React.createClass({ getInitialState: function(){ return { name: 'Tom', }; }, handleChange:function(event){ this.setState({name:event.target.value}); }, render: function(){ return <div> <HelloWorld name={this.state.name}></HelloWorld> <br /> <input type="text" onChange={this.handleChange} /> </div> }, }); React.render(<div style={style}><HelloUniverse></HelloUniverse></div>,document.body) </script> </body> </html>
- 屬性和狀態對比
屬性和狀態的相似點:
4.1.1都是純js對象
4.1.2都會觸發render函數更新
4.1.3都具有確定性
狀態相同,結果一定相同,這就是確定性。給定了相同的屬性或者相同的狀態,結果都是一樣的。
屬性 狀態
能否在父組件獲取初始值 可以 不可以
能否有父組件進行修改 可以 不可以
能否在組件內部設置默認值 可以 可以
能否在組件內部修改 不可以 可以
能否設置子組件的初始值 可以 不可以
能否修改子組件的初始值 可以 不可以 - 如何區分屬性和狀態
組件在運行時需要修改的數據就是狀態。
屬性的核心要點就是不能修改! - 屬性和狀態實戰
編寫一個簡單的文章評論框
第一步:分析構成項目的組件。 第二步:分析組件的關系及數據傳遞 第三步:編寫代碼
6.1添加兩個組件,並用React.render渲染到頁面上,Content內容組件,Comment評論框組件。
<!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.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> //子組件 var Content=React.createClass({ render:function(){ return <p>content</p>; }, }); //父組件 var Comment = React.createClass({ render:function(){ //我們現在東西是寫死的,下一個例子的寫法是動態的生成。 return <Content></Content>; }, }); React.render(<Comment></Comment>,document.body); </script> </body> </html>
6.2在Comment里面添加一個下拉列表
<!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.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> //子組件 var Content=React.createClass({ render:function(){ return <p>content</p>; }, }); //父組件 var Comment = React.createClass({ render:function(){ //我們現在東西是寫死的,下一個例子的寫法是動態的生成。 return <div> <select> <option value="1">Tim</option> <option value="2">Jerry</option> <option value="3">LiMing</option> <option value="4">Jhon</option> </select> <Content></Content> </div> }, }); React.render(<Comment></Comment>,document.body); </script> </body> </html>
6.3在父組件comment里面添加一個getInitialState組件,names屬性的值是一個數組。這樣的好處是后面如果加入新的回復對象,我們可以進行更新。<!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.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> //子組件 var Content=React.createClass({ render:function(){ return <p>Content</p>; }, }); //父組件 var Comment = React.createClass({ getInitialState:function(){ return { names:["Tim","John","Hank"] }; }, render:function(){ var options=[]; for(var option in this.state.names){ options.push(<option value={option}>{this.state.names[option]}</option>) }; return <div> <select> {options} </select> <Content></Content> </div> }, }); React.render(<Comment></Comment>,document.body); </script> </body> </html>
6.4(我們這個例子有bug,選中以后彈出的是選項的角標,6.5中會有講解。)父組件comment里面增加了handleSelect函數來處理select的選中事件,然后在select里面添加onChange事件,並且給他綁定handleSelect事件,當我們在select選中選項的時候,就會觸發handleSelect事件,他會將我們選中的值賦值給state中的selectName屬性,由於我們要將這個selectName賦值給我們的子組件,所以需要在getInitialState里面初始化一個selectName,並且賦值為空,最后我們在content組件里面給selectName賦值,他的值為this.state.selectName,也就是我們選中的名字,還要注意我們需要在content組件中,將我們拿到的組件的屬性顯示出來。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>彈出1 2 3</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> //子組件 var Content=React.createClass({ render:function(){ return <p>{this.props.selectName}</p>; }, }); //父組件 var Comment = React.createClass({ getInitialState:function(){ return { names:["Tim","John","Hank"], selectName:'', }; }, handleSelect:function(event){ this.setState({selectName:event.target.value}); }, render:function(){ var options=[]; for(var option in this.state.names){ options.push(<option value={option}>{this.state.names[option]}</option>) }; return <div> <select onChange={this.handleSelect}> {options} </select> <Content selectName={this.state.selectName}></Content> </div> }, }); React.render(<Comment></Comment>,document.body); </script> </body> </html>
6.5在我做這個例子的時候,由於書寫錯誤,導致6.4中彈出的是選項的角標,注意看for循環里面的修改。
<!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.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> //子組件 var Content=React.createClass({ render:function(){ return <p>{this.props.selectName}</p>; }, }); //父組件 var Comment = React.createClass({ getInitialState:function(){ return { names:["Tim","John","Hank"], selectName:'', }; }, handleSelect:function(event){ this.setState({selectName:event.target.value}); }, render:function(){ var options=[]; for(var option in this.state.names){ options.push(<option value={this.state.names[option]}>{this.state.names[option]}</option>) }; return <div> <select onChange={this.handleSelect}> {options} </select> <Content selectName={this.state.selectName}></Content> </div> }, }); React.render(<Comment></Comment>,document.body); </script> </body> </html>
6.6修改子組件,在content里面添加了一個getInitialState,里面返回了一個text,在render里面添加了一個textarea,
<!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.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> //子組件 var Content=React.createClass({ getInitialState:function(){ return { text: "replay To:"+this.props.selectName, }; }, render:function(){ return <div> <textarea placeholder="請輸入..."></textarea> </div> }, }); //父組件 var Comment = React.createClass({ getInitialState:function(){ return { names:["Tim","John","Hank"], selectName:'', }; }, handleSelect:function(event){ this.setState({selectName:event.target.value}); }, render:function(){ var options=[]; for(var option in this.state.names){ options.push(<option value={this.state.names[option]}>{this.state.names[option]}</option>) }; return <div> <select onChange={this.handleSelect}> {options} </select> <Content selectName={this.state.selectName}></Content> </div> }, }); React.render(<Comment></Comment>,document.body); </script> </body> </html>
6.7給content添加一個handleChange函數,在getInitialState里面添加一個inputText,給textarea綁定handleChange函數,將我輸入的內容賦值給inputText。頁面無變化。<!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.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> //子組件 var Content=React.createClass({ getInitialState:function(){ return { text: "replay To:"+this.props.selectName, inputText:"", }; }, handleChange:function(){ this.setState({inputText:event.target.value}); }, render:function(){ return <div> <textarea onChange={this.handleChange} placeholder="請輸入..."></textarea> </div> }, }); //父組件 var Comment = React.createClass({ getInitialState:function(){ return { names:["Tim","John","Hank"], selectName:'', }; }, handleSelect:function(event){ this.setState({selectName:event.target.value}); }, render:function(){ var options=[]; for(var option in this.state.names){ options.push(<option value={this.state.names[option]}>{this.state.names[option]}</option>) }; return <div> <select onChange={this.handleSelect}> {options} </select> <Content selectName={this.state.selectName}></Content> </div> }, }); React.render(<Comment></Comment>,document.body); </script> </body> </html>
6.8增加了handleSubmit事件,把我們text和inputText里面的內容輸出到控制台。render里面新增一個button,並且給他綁定handleSubmit函數,注意button事件為onClick,不是onChange.可以打開控制台看看。<!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.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> //子組件 var Content=React.createClass({ getInitialState:function(){ return { text: "replay To:"+this.props.selectName, inputText:"", }; }, handleChange:function(){ this.setState({inputText:event.target.value}); }, handleSubmit:function(){ console.log(this.state.text + "\n" + this.state.inputText); }, render:function(){ return <div> <textarea onChange={this.handleChange} placeholder="請輸入..."></textarea> <button onClick={this.handleSubmit}>submit</button> </div> }, }); //父組件 var Comment = React.createClass({ getInitialState:function(){ return { names:["Tim","John","Hank"], selectName:'', }; }, handleSelect:function(event){ this.setState({selectName:event.target.value}); }, render:function(){ var options=[]; for(var option in this.state.names){ options.push(<option value={this.state.names[option]}>{this.state.names[option]}</option>) }; return <div> <select onChange={this.handleSelect}> {options} </select> <Content selectName={this.state.selectName}></Content> </div> }, }); React.render(<Comment></Comment>,document.body); </script> </body> </html>
6.9上面那個實力有錯誤,我們需要修改一下。父組件中,會把select內容傳遞給selectName,沒有問題。在子組件content里面,由於使用了getInitialState函數,當我們父組件select再次發生變化的時候,getInitialState不會再次調用,導致我們的replay to 后面沒有內容,所以我們需要將它放在console里面,也就是最后。我們在getInitialState里面移除了text,把它放在最后使用它的位置。
<!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.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script> <script type="text/jsx"> //子組件 var Content=React.createClass({ getInitialState:function(){ return { //由於這里不會更新,所以我們下拉選人的時候,控制台沒有報,我們修改一下 //text: "replay To:"+this.props.selectName, inputText:"", }; }, handleChange:function(){ this.setState({inputText:event.target.value}); }, handleSubmit:function(){ //把計算的部分放到我們要用到的地方,要不輸出的時候,不是我們最新的。 console.log("replay To: "+this.props.selectName+ "\n" + this.state.inputText); }, render:function(){ return <div> <textarea onChange={this.handleChange} placeholder="請輸入..."></textarea> <button onClick={this.handleSubmit}>submit</button> </div> }, }); //父組件 var Comment = React.createClass({ getInitialState:function(){ return { names:["Tim","John","Hank"], selectName:'', }; }, handleSelect:function(event){ this.setState({selectName:event.target.value}); }, render:function(){ var options=[]; for(var option in this.state.names){ options.push(<option value={this.state.names[option]}>{this.state.names[option]}</option>) }; return <div> <select onChange={this.handleSelect}> {options} </select> <Content selectName={this.state.selectName}></Content> </div> }, }); React.render(<Comment></Comment>,document.body); </script> </body> </html>