前端筆記之React(二)組件內部State&React實戰&表單元素的受控

1、組件內部的State

1.1 state

state叫狀態,是每個類式組件都有的屬性,但函數式組件,沒有statehtml

state是一個對象,什麼值均可以定義。react

在任何類式組件的構造函數中,能夠用this.state = {} 來給類的實例添加state屬性,表示「狀態」。npm

render()函數的return中,能夠用{this.state.a}插值來顯示出每個屬性的值編程

 

import React from "react";

export default class App extends React.Component {
    constructor() {
        super();
        //組件的內部狀態,state屬性
        this.state = {
            a : 100 }
    }
    render() {
        return <div>
               <h1>{this.state.a}</h1>
        </div>
    }
}


1.2 setState()

點擊按鈕以後,讓1001數組

import React from "react";
import ReactDOM from "react-dom";
export default class App extends React.Component {
    constructor() {
        super();
        this.state = {
            a : 100
        }
    }
    render() {
        return <div>
            <button onClick={()=>{
                this.setState({
                    a : this.state.a + 1 })
            }}>按我</button>
            <h1>{this.state.a}</h1>
        </div>
    }
}

注意:dom

 React中事件監聽,要寫在標籤上。ide

 事件名onClick而不是onclick,注意大寫字母。由於React將事件名都進行了拓展,因此onClickReact本身的方法。同理,全部事件名on後面的首字母都是大寫onMouseEnteronDoubleClickonKeyDown函數

 onClick=後面緊跟{},表示插值。大括號中是一個箭頭函數,這個函數必須是箭頭函數,不然this錯誤。學習

<button onClick={()=>{ }}></button>

 

setState是定義在React.Component類中的方法,因此任何一個組件都可以無腦調用this.setState()。表示「設置state」。ui

this.setState({要設置的k : 新的v});

 

setState不只可以改變實例的state的屬性值,並且能產生視圖刷新。而若是不用setState(),只是讓state的屬性值進行改變,視圖是不刷新的。

錯誤的:

export default class App extends React.Component {
    constructor() {
        super();
        this.state = {
            a : 100
        }
    }
    render() {
        return <div>
            <button onClick={()=>{
                this.state.a++;
            }}>按我</button>
            <h1>{this.state.a}</h1>
        </div>
    }
}

1.3提煉出事件處理函數

以前的onClick後面直接跟上了{()=>{}},實際上能夠提出來,封裝成函數。

import React from "react";
export default class App extends React.Component{
    constructor(){
        super();
        this.state = {
            a : 100
        }
    }
 add(){ this.setState({
            a:this.state.a + 1 });
    }
    render(){
        return <div>
            <h1>{this.state.a}</h1>
            <button onClick={()=>{this.add()}}>按我加1</button>
        <button onClick={this.add.bind(this)}>按我加1</button>
        </div>
    }
};

方法的執行能夠不經過箭頭函數,可是很差,由於這樣寫不能傳遞參數

注意,提煉成爲組件的方法(實際上寫在了構造器的prototype上,實例的原型上),onClick調用的時候,必須寫bind(this),將調用的這個函數的上下文綁定爲組件的實例能夠當作是一個固定的語法!

 

如何傳參數?

import React from "react";
import ReactDOM from "react-dom";
export default class App extends React.Component {
    constructor() {
        super();
        this.state = {
            a : 100
        }
    }
    //單擊事件的處理函數
  add(n){ this.setState({ a : this.state.a + n }); }

    render() {
        return <div>
            <button onClick={()=>{this.add(1)}}>按我</button>
            <button onClick={()=>{this.add(2)}}>按我</button>
            <button onClick={()=>{this.add(3)}}>按我</button>
             
            <h1>{this.state.a}</h1>
            
            <div style={{
                "width" : this.state.a + "px",
                "height": this.state.a + "px",
                "backgroundColor" : "orange",
                "transform" : "rotate(" + this.state.a + "deg)" 
            }}></div>
        </div>
    }
}

1.4 MVVM模式

ReactVue以及已通過時Angular都是MVVM模式,都有一個特色,就是:

數據驅動視圖:數據變化了,視圖自動變化

 

MVVM模式經典的4句話:

1)數據變化,視圖就會自動變化

2)視圖變化的緣由,必定是數據變化了

3)數據是視圖的本質

4)視圖是數據的表現

 

咱們之後不再用關心DOM結構了,只關心數據,數據變化,視圖自動變化

 

如今只須要用setState()來改變組件的實例的state,視圖就會自動變化,後面你將知道,視圖變化的緣由是由於組件進入了新的生命週期,也將知道視圖更新的效率由於有的Virtual DOM從而變的很快。


2、案例

2.1組件state的增刪改查

知識點:html標籤能夠加refreference引用)屬性,在組件內部能夠經過this.refs來引用這個DOM元素。

<input type="text" ref="nameTxt"/>

 

獲取標籤的值:

var val = this.refs.nameTxt.value
import React from "react";
export default class App extends React.Component {
    constructor() {
        super();
        this.state = {
            arr: [
                { "id": 1, "name": "小明", "age": 12, "sex": "男" },
                { "id": 2, "name": "小紅", "age": 13, "sex": "女" },
                { "id": 3, "name": "小剛", "age": 14, "sex": "男" },
                { "id": 4, "name": "小白", "age": 15, "sex": "男" }
            ]
        }
    }
    //添加學員
   addList(){ //獲取值  var name = this.refs.nameTxt.value; var age = this.refs.ageTxt.value; var sex = this.refs.sexTxt.value; //改變state必須用setState()方法 this.setState({ arr:[ // 原來的項是不變 ...this.state.arr, // 只增長一項 {  //id : 6 id:this.state.arr.reduce((a,b)=>{ return a.id > b.id ? a : b }).id + 1, name, age, sex } ] }) }
    //刪除列表
   delList(id){ this.setState({ arr:this.state.arr.filter(item=>item.id !=id) }); }
    render(){
        return <div>
            <p>姓名:<input type="text" ref="nameTxt" /></p>
            <p>年齡:<input type="text" ref="ageTxt" /></p>
            <p>性別:<input type="text" ref="sexTxt" /></p>
            <button onClick={()=>{this.addList()}}>添加</button>
            <ul>
                {
                    this.state.arr.map(item=>{
                        return <li key={item.id}>
                            {item.id} -- {item.name}--年齡{item.age}歲,性別{item.sex}
                            <button onClick={()=>{this.delList(item.id)}}>刪除</button>
                        </li> })
                }
            </ul>
        </div>
    }
}

React中都是純函數編程。


2.2調色板

import React from "react";
export default class App extends React.Component{
    constructor(){
        super();
        this.state = { r : 20, g : 200, b : 123 }
    }
    //變化顏色
    setColor(k,v){ this.setState({ [k] : v }) }
    render(){
        return <div>
            <div style={{
"width":"200px",
"height":"200px",
"background":`rgb(${this.state.r},${this.state.g},${this.state.b})`}}>
</div>
            <p>
                <input
                    type="range"
                    max={255}
                    value = {this.state.r}
                    onChange={(e)=>{this.setColor("r",e.target.value)}}
                />
                <span>{this.state.r}</span>
            </p>
            <p>
                <input
                    type="range"
                    max={255}
                    value={this.state.g}
                    onChange={(e)=>{this.setColor("g",e.target.value)}}
                />
                <span>{this.state.g}</span>
            </p>
            <p>
                <input
                    type="range"
                    max={255}
                    value={this.state.b}
                    onChange={(e)=>{this.setColor("b",e.target.value)}}
                />
                <span>{this.state.b}</span>
            </p>
        </div>
    }
};
若是一個表單元素,和state的一個值進行了「關聯」:
1)state的值就是表單元素的值;
2)改變表單元素,就會改變state的值。
咱們叫作這個表單元素和數據進行了「雙向數據綁定」,也叫做表單元素「受控」。

React中,實現雙向數據綁定(實現表單元素受控)的套路:

加上value屬性實現從state中「要」值;

加上onChange事件實現「設置」state的值。

若是一個組件內部,全部表單元素都有state的數據,進行了雙向數據綁定,此時稱爲「受控組件」。

 

<p>
    <input 
        type="range" 
        min={0} 
        max={255} 
        value={this.state.b}
        onChange={(e)=>{this.setColor("b" , e.target.value)}}
    />
</p>

簡單的說「一個表單元素受控」,等價於「這個表單元素有一個值和他雙向綁定」。

全部的表單元素受控,咱們就說組件受控。


 

2.3微博發佈框

結構:輸入框、發佈按鈕、內容清空按鈕,一串文字「當前88/140字」

當內容超過140字,則發佈按鈕不能點,文字變紅

實時顯示字數,當框中有內容,按鈕能夠點擊清空

 

若是讓一個元素是否使用某一個類,React官方建議安裝classnames依賴

npm install --save classnames
import React from "react";
import classnames from "classnames";
export default class App extends React.Component{
    constructor(){
        super();
        this.state = { txt: "" }
    }
    render(){
        const length = this.state.txt.length;
        return <div>
            <textarea
                cols="30"
                rows="10"
                value={this.state.txt}
                onChange={(e)=>{this.setState({txt:e.target.value})}}
            >
            </textarea>
            <p>
                 <button disabled={length == 0 || length>140}>發佈</button>
                 <button disabled={length==0} onClick={()=>{this.setState({txt:""})}}>
清空
</button>
                  <span className={classnames({"danger":length > 140})}>
已寫{length}/140字
</span>
            </p>
        </div>
    }
};

3、表單元素的受控

什麼是受控?

一個表單元素的value值和state中某個屬性息息相關:

這個表單元素的值,來自於state中的屬性

更改表單元素的值,可以更改state中的值

也叫雙向數據綁定,不過React中稱爲「受控組件(Controller Component)」

Vue才叫雙向數據綁定。

React中,全部表單元素的受控方式同樣,都是value={}onChange={}

 

3.1單行和多行文本框

import React from "react";
var classNames = require('classnames');
export default class App extends React.Component {
    //構造函數
    constructor() {
        super();
        this.state = {
            a : "我是默認的a值", b : 50,
        }
    }
    render() {
        return (
            <div>
               <p>
                    <input type="text"
                        value={this.state.a}
                        onChange={(e) => { this.setState({ a: e.target.value }) }}
                    />
                    <span>{this.state.a}</span>
               </p>
              
                <p>
                    <input type="range"
                        value={this.state.b}
                        onChange={(e) => { this.setState({ b: e.target.value })}}
                    />
                    <span>{this.state.b}</span>
                </p>
            </div>
        )
    }
};

 

3.2下拉菜單

this.state = {
    c : "廣州"
}
<p>
    <select 
        value={this.state.c} 
        onChange={(e) => { this.setState({ c: e.target.value }) }}
    >
        <option value="廣州">廣州</option>
        <option value="深圳">深圳</option>
        <option value="佛山">佛山</option>
        <option value="東莞">東莞</option>
        <option value="雲浮">雲浮</option>
    </select>
    <span>{this.state.c}</span>
</p>

3.3單選按鈕

單選按鈕受控的套路:checked={}value="" onChange={}

<p>
    <input 
        type="radio" 
        name="sex" 
        value="男" 
        checked={this.state.e == '男'}
        onChange={(e) => { this.setState({ d: e.target.value }) }}
    />男
    <input 
        type="radio" 
        name="sex" 
        value="女" 
        checked={this.state.e == '女'}
        onChange={(e) => { this.setState({ d: e.target.value })}}
    />女
    <span>{this.state.d}</span>
</p>

3.4複選框受控

複選框和上面全部表單元素都不同:

要靠checked={}獲得值,要判斷includes

要寫一個函數,傳入將要驗證的值,根據這個值是否是已經在數組中,再決定刪除、添加。

 

setF(word){
    if(this.state.f.includes(word)){
        //若是這個值已經在f數組中,則刪除
        this.setState({
            f : this.state.f.filter(item=>item != word) });
    }else{
        //若是這個值不在f數組中,則加入數組
        this.setState({
            f : [...this.state.f, word] });
    }
}
<p>
    愛好:
    <input 
        type="checkbox" 
        value="看書"
        checked={this.state.f.includes('看書')}
        onChange={(e) => { this.setF("看書") }}
    />看書
    <input 
        type="checkbox" 
        value="游泳"
        checked={this.state.f.includes('游泳')}
        onChange={(e) => { this.setF("游泳") }}
    />游泳
    <input 
        type="checkbox" 
        value="打球"
        checked={this.state.f.includes('打球')}
        onChange={(e) => { this.setF("打球") }}
    />打球
    <span>{this.state.f.join(',')}</span>
</p>

3.5可選擇的表單類-案例

這個案例學習DOM的上下樹

控制元素是否顯示或隱藏,不要用display屬性

而是用三元運算符控制DOM元素是否上下樹。若是上數寫標籤,若是不上樹寫null

不論是作什麼案例,都是兩大部分:①、寫JSX侵入DOM標籤,②、事件監聽,改變state

 

import React from "react";
export default class App extends React.Component{
    // 構造函數
    constructor(){
        super();
       this.state = {
            arr:[
                { "id": 1, "name": "小明", "age": 12, "sex": "男" },
                { "id": 2, "name": "小紅", "age": 13, "sex": "女" },
                { "id": 3, "name": "小剛", "age": 14, "sex": "男" },
                { "id": 4, "name": "小白", "age": 15, "sex": "男" }
            ],
            showCols:['姓名',"年齡","性別"]
       }
    }
    setChangeCols(word){ if(this.state.showCols.includes(word)){ this.setState({ showCols:this.state.showCols.filter(item=>item !=word) }) }else{ this.setState({ showCols:[ ...this.state.showCols, word ] }); }; }
   render(){ return <div>
            <div>
                <input type="checkbox"
                    value="姓名"
                    checked={this.state.showCols.includes("姓名")}
                    onChange={(e)=>{this.setChangeCols("姓名")}}
                 />姓名
                <input type="checkbox"
                    value="年齡"
                    checked={this.state.showCols.includes("年齡")}
                    onChange={(e)=>{this.setChangeCols("年齡")}}
                 />年齡
                <input type="checkbox"
                    value="性別"
                    checked={this.state.showCols.includes("性別")}
                    onChange={(e)=>{this.setChangeCols("性別")}}
                 />性別
            </div>
            <span>{this.state.showCols}</span>
            <table>
                <tbody>
                   <tr>
                        <th>ID</th> {this.state.showCols.includes("姓名") ? <th>姓名</th> : null}
                      {this.state.showCols.includes("年齡") ? <th>年齡</th> : null}
                       {this.state.showCols.includes("性別") ? <th>性別</th> : null}
                   </tr>
                   {
                        this.state.arr.map(item=>{
                            return <tr key={item.id}>
                               <td>{item.id}</td> {this.state.showCols.includes("姓名") ? <td>{item.name}</td>:null}
                             {this.state.showCols.includes("年齡") ? <td>{item.age}</td>:null}
                            {this.state.showCols.includes("性別") ? <td>{item.sex}</td>:null}
                            </tr> })
                   }
                </tbody>
            </table>
        </div> }
};

 

3.6三級聯動-案例

 

額外提供的數據:

[
    {

        "name" : "廣東省",
        "city" : [
            {
                "name":"廣州",
                "area":[
                    "天河區",
                    "白雲區",
                    ...
                ]            
            },
            {
                "name":"深圳",
                "area":[
                    "福田區",
                    "南山區"
                ]
            }
            ....
        ]
    },
    ....
]
示例代碼

 

forEachfiltermapreduce函數都是表達式,而不是語句體。iffor語句是語句體。

import React from "react";
import city from "./city.js";
export default class App extends React.Component{
    constructor(){
        super();
        this.state = { "province":"廣東省", "city":"廣州市", "area":"天河區" }
    }
    render(){
        //循環遍歷省份
        const showProvinces = ()=>{
            //遍歷city數據,提取每一項省份成爲option
            var arr=[];
          city.forEach((item,index)=>{
                arr.push(<option key={index} value={item.name}>{item.name}</option>)
        });
            return arr;
      }

        //循環遍歷市,顯示哪個城市,須要根據state的province屬性的省份選擇城市
        const showCitys = ()=>{
            var arr = [];
            // 先篩選省份,再次篩選對應城市列表
        var cityArr = city.filter(item=>item.name == this.state.province)[0].city;
            cityArr.forEach((item,index)=>{
                arr.push(<option key={index} value={item.name}>{item.name}</option>)
          });
            return arr;
        };

        //顯示區縣
       const showAreas = ()=>{
            var arr = [];
               // 先篩選省份,再次篩選對應城市列表
        var cityArr = city.filter(item=>item.name == this.state.province)[0].city;
        //根據市,得出區,只需選擇區的第一項
       var areaArr = cityArr.filter(item => item.name == this.state.city)[0].area
       //最後根據篩選出的市,遍歷區
        areaArr.forEach((item,index)=>{
                arr.push(<option key={index} value={item}>{item}</option>)
           })
            return arr;
     }

        return <div>
            省份:<select
                    value={this.state.province}
                    onChange={(e)=>{
                        this.setState({ "province":e.target.value, "city":city.filter(item=>item.name == e.target.value)[0].city[0].name })
                }}
                    >
                       {showProvinces()} </select>
            城市:<select
                    value={this.state.city}
                    onChange={(e)=>{
                       this.setState({"city":e.target.value})
                   }}
                     >
                       {showCitys()} </select>  
            區縣:<select
                    value={this.state.area}
                    onChange={(e)=>{
                       this.setState({"area":e.target.value})
                }}
                     >
                        {showAreas()} </select>
        </div>
    }
};
相關文章
相關標籤/搜索