前端笔记之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>
    }
};
相关文章
相关标签/搜索