React學習筆記-8-屬性和狀態詳解


  1. 屬性的含義和用法
    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} />

     

    第三種:最不常用的,setProps可以設置組件的屬性,他接受的參數是一個對象,他會用這個對象來更新屬性,但是在實際使用中,很好用這個因為我們是不能夠在組件內部去修改屬性的,這樣會違背react的設計原則。在組件外部直接用上面兩種。
    instance.setProps({name:"Tom"})



  2. 實例
    <!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>

     

  3. 狀態的含義和用法
    狀態 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. 屬性和狀態對比
    屬性和狀態的相似點:
    4.1.1都是純js對象
    4.1.2都會觸發render函數更新
    4.1.3都具有確定性
       狀態相同,結果一定相同,這就是確定性。給定了相同的屬性或者相同的狀態,結果都是一樣的。

                                               屬性          狀態
    能否在父組件獲取初始值                 可以             不可以
    能否有父組件進行修改                     可以            不可以
    能否在組件內部設置默認值                可以           可以
    能否在組件內部修改                         不可以           可以
    能否設置子組件的初始值                  可以               不可以
    能否修改子組件的初始值                   可以              不可以




  5. 如何區分屬性和狀態
    組件在運行時需要修改的數據就是狀態。
    屬性的核心要點就是不能修改!


  6. 屬性和狀態實戰
    編寫一個簡單的文章評論框
    第一步:分析構成項目的組件。         第二步:分析組件的關系及數據傳遞        第三步:編寫代碼

    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>

     







免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM