React组件实例的三大核心属性

React组件实例的三大核心属性

state

  • state 是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)
  • 组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)
    即:组件—>状态—>驱动—>页面

初始化state

1.创建一个有状态的组件

<body>
    <div id="test"></div>
    <script type="text/babel">
        // 1.创建组件
        class Weather extends React.Component {
            constructor(props) {
                super(props);
                // 初始化状态
                this.state = { isHot: true };
            }
            render() {
                // 解构赋值
                const {isHot} = this.state;
                return <h1>今天天气很{isHot ? "炎热" : "寒冷"}</h1>
            }
        }
        // 2.渲染组件到页面
        ReactDOM.render(<Weather />, document.getElementById("test"))
    </script>
</body>

React中事件绑定

  • 响应事件函数名采用驼峰命名法:onClick、onBlur
  • 用法:<h1 onClick={回调函数}></h1>
render() {
 // 解构赋值
 return <h1 onClick={this.changeWeather}></h1>
}
changeWeather() {
 console.log('今天天气真好!');
}

错误写法:

// 错误写法一
<h1 onClick='this.changeWeather'></h1>
// 错误写法二
<h1 onClick={this.changeWeather()}></h1>//这种写法会直接执行,相当于直接调用

类组件中自定义方法中this问题

  • 通过组件实例调用的方法中的this是组件实例对象
  • 组件中render方法中的this为组件实例对象,render方法是由组件实例对象调用的
  • 在类组件中的函数方法系统默认都默认开启了局部严格模式
  • 组件自定义方法会放在组件对象的原型上,供组件实例使用
  • 在类组件中除了render()函数以外,自定义方法一般是作为事件的回调,所以不是通过实例调用的,是直接调用,又因为类组件中的方法默认开启了局部的严格模式,所以个人在类组件写的函数方法中的thisundefined
 render() {
     // 解构赋值
     const { isHot } = this.state;
     return <h1 onClick={this.changeWeather}>今天天气很{isHot ? "炎热" : "寒冷"}</h1>
 }
 changeWeather() {
     console.log(this);// undefined
 }

在这里插入图片描述

解决类中this指向问题

  • 强制绑定this:通过函数对象的bind()
  1. 在构造器中绑定this,this.changeWeather = this.changeWeather.bind(this)
<script type="text/babel">
    // 1.创建组件
    class Weather extends React.Component {
        constructor(props) {
            super(props);
            // 初始化状态
            this.state = { isHot: true };
            // 解决changeWeather中this指向问题
            this.changeWeather = this.changeWeather.bind(this)
        }
        render() {
            // 解构赋值
            const { isHot } = this.state;
            return <h1 onClick={this.changeWeather}>今天天气很{isHot ? "炎热" : "寒冷"}</h1>
        }
        changeWeather() {
            // changeWeather放在哪里? ———— Weather的原型对象上,供组件实例使用
            // 由于changeWeather是作为onClick的回调,所以不是通过实例调用,是直接调用
            // 类中的方法默认开启了局部的严格模式
            console.log(this);// undefined
        }
    }
    // 2.渲染组件到页面
    ReactDOM.render(<Weather />, test)
</script>
  1. 在回调函数中绑定this
<script type="text/babel">
    // 1.创建组件
    class Weather extends React.Component {
        constructor(props) {
            super(props);
            // 初始化状态
            this.state = { isHot: true };
            // 解决changeWeather中this指向问题
            // this.changeWeather = this.changeWeather.bind(this)
        }
        render() {
            // 解构赋值
            const { isHot } = this.state;
            // 解决changeWeather中this指向问题
            return <h1 onClick={this.changeWeather.bind(this)}>今天天气很{isHot ? "炎热" : "寒冷"}</h1>
        }
        changeWeather() {
            console.log(this);// undefined
        }
    }
    // 2.渲染组件到页面
    ReactDOM.render(<Weather />, test)
</script>
  • 使用箭头函数解决this指向问题
    <script type="text/babel">
        // 1.创建组件
        class Weather extends React.Component {
            constructor(props) {
                super(props);
                // 初始化状态
                this.state = { isHot: true };
                // 方法1:解决changeWeather中this指向问题
                // this.changeWeather = this.changeWeather.bind(this)
            }
            render() {
                // 解构赋值
                const { isHot } = this.state;
                // 方法2:解决changeWeather中this指向问题
                return <h1 onClick={this.changeWeather}>今天天气很{isHot ? "炎热" : "寒冷"}</h1>
            }
            // 方法:3:解决changeWeather中this指向问题
            changeWeather = () => {
                console.log(this);// undefined
            }
        }
        // 2.渲染组件到页面
        ReactDOM.render(<Weather />, test)
    </script>

通过setState方法修改状态(state)

  • 状态(state)不可直接更改,需要使用内置API的setState方法去更新
  • setState方法的参数是一个对象
  • 传入的对象会和原来的状态进行合并,如果同名就直接覆盖值
  • 每次setState方法修改状态(state)就会调动一次render()方法
<script type="text/babel">
    // 1.创建组件
    class Weather extends React.Component {
        constructor(props) {
            super(props);
            // 初始化状态
            this.state = { isHot: true };
            // 方法1:解决changeWeather中this指向问题
            // this.changeWeather = this.changeWeather.bind(this)
        }
        render() {
            // 解构赋值
            const { isHot } = this.state;
            // 方法2:解决changeWeather中this指向问题
            return <h1 onClick={this.changeWeather}>今天天气很{this.state.isHot ? "炎热" : "寒冷"}</h1>
        }
        // 方法:3:解决changeWeather中this指向问题
        changeWeather = () => {
            const isHot = this.state.isHot;
            // 更新状态
            this.setState({
                isHot: !isHot
            })
            console.log(this.state.isHot);// undefined
        }
    }
    // 2.渲染组件到页面
    ReactDOM.render(<Weather />, test)
</script>

在这里插入图片描述

state的简写代码

 // 1.创建组件
class Weather extends React.Component {
    // 初始化状态
    state = { isHot: true };
    render() {
        const { isHot } = this.state;
        return <h1 onClick={this.changeWeather}>今天天气很{this.state.isHot ? "炎热" : "寒冷"}</h1>
    }
    // 自定义方法
    changeWeather = () => {
        const isHot = this.state.isHot;
        this.setState({
            isHot: !isHot
        })
    }
}
// 2.渲染组件到页面
ReactDOM.render(<Weather />, test)

props

  • 每个组件实例对象都会有props属性
  • 组件标签的属性都保存在props
  • 组件中的props是只读不可以通过this.props.属性名 ="属性"的方式去修改,会直接报错

props的基本使用

可以直接进行传参

<body>
    <div id="test"></div>
    <script type="text/babel">
    class Person extends React.Component{
        render(){
        	console.log(this.props);
            return (
                <ul>
                    <li>姓名:{this.props.name}</li>
                    <li>性别:{this.props.sex}</li>
                    <li>年龄:{this.props.age}</li>    
                </ul>
            )
        }
    }
    ReactDOM.render(<Person name="江流" age={19} sex="男"/>, document.getElementById("test"))
    </script>
</body>

在这里插入图片描述

批量传递props

使用构造字面量对象是使用展开语法
<Person {...p}/>

 class Person extends React.Component {
     render() {
         console.log(this.props);
         return (
             <ul>
                 <li>姓名:{this.props.name}</li>
                 <li>性别:{this.props.sex}</li>
                 <li>年龄:{this.props.age}</li>
             </ul>
         )
     }
 }
 const p = { name: "江流", age: 19, sex: "男" }
 ReactDOM.render(<Person {...p}/>, document.getElementById("test"))//这里的{...p}不是使用的扩展运算符,是在babel环境下传参的一种方式,只能在标签传参里面使用

props进行类型限制

  • 需要prop-types库,对标签属性进行类型、必要性的限制
  • 通过给组件上的添加并设置propTypes属性来限制props的类型,如果传入的prop类型有错误,React则会报出警告
  • 通过给组件上的添加并设置defaultProps属性来设置props的默认值
 <script type="text/babel">
     class Person extends React.Component {
         static propTypes = {
             name: PropTypes.string.isRequired, //限制name必传,且为字符串
             sex: PropTypes.string, //限制sex为字符串
             age: PropTypes.number, //限制age为数值
             speak: PropTypes.func, //限制speak为函数
         }
         static defaultProps = {
             sex: "男", //sex默认值为男
             age: 18, //age默认值为18
         }
         render() {
             console.log(this.props);
             return (
                 <ul>
                     <li>姓名:{this.props.name}</li>
                     <li>性别:{this.props.sex}</li>
                     <li>年龄:{this.props.age}</li>
                 </ul>
             )
         }
     }

     function speak() {
         console.log("我是谁?");
     }
     const speak2 = 1;
     ReactDOM.render(<Person name="江流儿" speak={speak} />, document.getElementById("test"))// 这里的...不是构造字面量
 </script>

props与构造器

 constructor(props){
     super(props)
 }

通常React中,构造函数仅仅用于以下两种情况

  • 通过给this.state赋值对象来初始化内部state
  • 为事件处理函数绑定实例(使用bind函数)
  • 在React组件挂载之前,会调用它的构造函数。在实现构造函数时,必须在其他语句之前调用super(props).否则,this.props在构造函数中会出undefined
  • 构造器中是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props

refs

在正常操作DOM真实节点时,需要采用DOM API来查找元素,但是这样违背了React的不直接操作DOM的理念,因此React提供了refs来定位虚拟DOM来操作真实DOM
组件内的标签可以定义ref属性来标识自己
有三种操作refs的方法,分别为:

  • 字符串形式的ref(过时的API)
  • 回调形式ref
  • createRef()形式

请勿过度使用Refs

字符串形式的ref

React官网不建议使用该方法

class Demo extends React.Component {
            showData = () => {
                const { input1 } = this.refs;
                alert(input1.value);
            }
            render() {
                return (
                    <div>
                        <input type="text" ref='input1' />
                        <button onClick={this.showData}>点我</button>
                    </div>
                )
            }
        }
        ReactDOM.render(<Demo />, document.getElementById("test"))

回调形式ref

通过给ref属性传递一个回调函数ref={currentNode => this.input1 = currentNode}(箭头函数简写)来创建一个ref

 class Demo extends React.Component {
     showData1 = () => {
         const { input1 } = this;
         alert(input1.value);
     }
     showData2 = () => {
         const { input2 } = this;
         alert(input2.value);
     }
     render() {
         console.log(this.refs);
         return (
             <div>
                 <input type="text" ref={currentNode => this.input1 = currentNode} />
                 <button onClick={this.showData1}>点我</button>

                 <input type="text" ref={currentNode => this.input2 = currentNode} />
                 <button onClick={this.showData2}>点我</button>
             </div>
         )
     }
 }
 ReactDOM.render(<Demo />, document.getElementById("test"))

回调refs的说明

  • 如果ref回调是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数null,然后第二次才会传入参数DOM元素。这是因为每次渲染是会创建一个新的函数实例,所以React清空旧的ref并且设置新的。通过ref的回调定义成class的绑定函数可以避免上诉问题,但是大多数情况下是无关紧要的

createRef形式

该形式是React官方推荐使用的方式
React.createRef方法调用后可以返回一个容器,该容器可以储存被ref所标识的节点
该容器是“专人专用”的,容器中仅有一个属性current,属性值即存放的节点

  class Demo extends React.Component {
      myRef1 = React.createRef();
      myRef2 = React.createRef();
      showData1 = () => {
          alert(this.myRef1.current.value);
      }
      showData2 = () => {
          alert(this.myRef2.current.value);
      }
      render() {
          console.log(this.refs);
          return (
              <div>
                  <input type="text" ref={this.myRef1} />
                  <button onClick={this.showData1}>点我</button>

                  <input type="text" ref={this.myRef2} />
                  <button onClick={this.showData2}>点我</button>
              </div>
          )
      }
  }
  ReactDOM.render(<Demo />, document.getElementById("test"))

事件处理

  1. 通过onXxx属性指定事件处理函数,例如onClick(注意大小写)
    a. React使用的是自定义(合成)事件,而不是使用原生DOM事件 —— 为了更好的兼容性
    b. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)——— 为了更好的高效
  2. 通过event.target也可以的得到发生事件的DOM元素对象 —— 不要过渡使用ref
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值