React全家桶:类--类式组件--state属性--事件绑定--类中方法的this--props属性--ref--事件处理

简介: React全家桶:类--类式组件--state属性--事件绑定--类中方法的this--props属性--ref--事件处理

写在前面

在最近看了React之后,一直觉得学的懵懵然,虽然很多大佬的手写笔记,写的都很不错,但是我一直没有我想要的那种细无巨细,比如类式组件this指向问题的追根溯源,又比如三大实例属性简写的由来,总之我还是决定做一份事无巨细的笔记。


那就让我们开始吧!


复习类相关的知识

创建实例对象

//创建一个Person类
    class Person {
    }
    let person1 = new Person();
    console.log(person1)
复制代码


  • 输出分解

fbc4e4f0e11a44e2b1b6994dcbbf709c_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

红色框代表new出来的实例对象

蓝色框代表这个实例对象是由Person这个类new出来的。

目的:为了区别实例是由哪个类new出来的


接收参数

  • 使用构造器方法(可以不写)

构造器也是在原型上的

//创建一个Person类
class Person {
        //构造器方法
        constructor(name,age){
                //构造器中的this是谁?—— 类的实例对象
                this.name = name
                this.age = age
        }
}
复制代码


注意: 构造器中的this是谁?—— 类的实例对象

  • 定义方法
//创建一个Person类
class Person {
        //构造器方法
        constructor(name,age){
                //构造器中的this是谁?—— 类的实例对象
                this.name = name
                this.age = age
        }
        //一般方法
        speak(){
                //speak方法放在了哪里?——类的原型对象上,供实例使用
                //通过Person实例调用speak时,speak中的this就是Person实例
                console.log(`我叫${this.name},我年龄是${this.age}`);
        }
}
复制代码


注意:

speak方法放在了哪里?——类的原型对象上,供实例使用

通过Person实例调用speak时,speak中的this就是Person实例

8c708a4758b94d7bbd431a0ec39021b5_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 继承

书写构造器之后必须书写super、必须放在带有使用this关键字的前面

super:调用父类的构造器

//创建一个Student类,继承于Person类
class Student extends Person {
        constructor(name,age,grade){
                super(name,age)
                this.grade = grade
                this.school = '尚硅谷'
        }
        //重写从父类继承过来的方法
        speak(){
                console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`);
                this.study()
        }
        study(){
                //study方法放在了哪里?——类的原型对象上,供实例使用
                //通过Student实例调用study时,study中的this就是Student实例
                console.log('我很努力的学习');
        }
}
复制代码


  • 调用方法

如果不重写方法,那么就会调用父类提供的方法,这个方法会通过原型链在person实例的原型对象上找到。

class Student extends Person {
        constructor(name,age,grade){
                super(name,age)
                this.grade = grade
                this.school = '尚硅谷'
        }
}
复制代码

a61906b7967e41ac84d5f6c913d4f039_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 重写方法
//创建一个Student类,继承于Person类
class Student extends Person {
        constructor(name,age,grade){
                super(name,age)
                this.grade = grade
                this.school = '尚硅谷'
        }
        //重写从父类继承过来的方法
        speak(){
                console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`);
                this.study()
        }
        study(){
                //study方法放在了哪里?——类的原型对象上,供实例使用
                //通过Student实例调用study时,study中的this就是Student实例
                console.log('我很努力的学习');
        }
}
复制代码


e116756cb37649b78502a6f630bac953_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


蓝色框的方法在student实例的原型对象上、红色框的方法在person实例的原型对象上。

调用方法采用就近原则,通过原型链调用最先找到的那个方法。

-总结:

1.类中的构造器不是必须要写的,要对实例进行一些初始化的操作,如添加指定属性时才写。
2.如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的。
3.类中所定义的方法,都放在了类的原型对象上,供实例去使用。
复制代码


类式组件

类名或者函数名就是组件名

创建类式组件

  • 必须继承React内置一个类

必须继承React.Component

  • 可以省略构造器

传送门

react.docschina.org/

9caae4961be84baf815c5e8065edab06_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 书写必备的三个条件
  1. 必须继承React.Component
  2. 必学书写render方法
  3. redner必须有返回值
<script type="text/babel">
        //1.创建类式组件
        class MyComponent extends React.Component {
                render(){
                        //render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。
                        console.log('render中的this:',this);
                        return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
                }
        }
        //2.渲染组件到页面
        ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>
复制代码


  • render是放在哪里的?—— MyComponent的原型对象上,供实例使用。

226a165800764dcd9be1a1c6b8598a75_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 执行了ReactDOM.render(.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
  2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
  3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
复制代码


  • render中的this是谁?

MyComponent的实例对象 <=> MyComponent组件实例对象。

console.log('render中的this:',this);

87b5f1a1000c4dfab709d08f40f2e73c_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


对state的理解

简单组件、复杂组件

有无“状态”,有就是复杂组件、无就是简单组件


组件实例的三大核心属性

state、prrops、refs


初始化state

组件三大核心属性:state

  • 向state属性传值(书写构造器)

1、构造器传值:接受props

传送门

react.docschina.org/

0acd8eef153a4697bba50cb365340af7_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


2、必须调用super

super(props)
复制代码


如果书写构造器不调用就会报错

31a8a7e047234afe9bed5527e4249cec_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 给state赋值是一个对象
//初始化状态
this.state = {isHot:false,wind:'微风'}
复制代码


  • 渲染到页面
<script type="text/babel">
    //1.创建组件
    class Weather extends React.Component{
      constructor(props){
        super(props)
        //初始化状态
        this.state = {isHot:false}
      }
      render(){
        return <h1 今天天气很{isHot ? '炎热' : '凉爽'}</h1>
      }
    }
    //2.渲染组件到页面
    ReactDOM.render(<Weather/>,document.getElementById('test'))
  </script>
复制代码


react中事件绑定

原生事件的绑定

  • 3种类型
<body>
        <button id="btn1">按钮1</button>
        <button id="btn2">按钮2</button>
        <button onclick="demo()">按钮3</button>
</body>
<script type="text/javascript" >
        const btn1 = document.getElementById('btn1')
        btn1.addEventListener('click',()=>{
                alert('按钮1被点击了')
        })
        const btn2 = document.getElementById('btn2')
        btn2.onclick = ()=>{
                alert('按钮2被点击了')
        }
        function demo(){
                alert('按钮3被点击了')
        }
</script>
复制代码


  • 实现效果

96943970ddde4ccb90163a1a9833fe1f_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 在React依然可以使用原生绑定事件(只要能绑定到render方法返回的标签就行)

实际中不会这样使用614b15803dc6441fbba7b84712713b06_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png



  • on类api得驼峰命名

128d33f0ceaa41a5ad31a7fec14c7b7a_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


1、为onClick赋值一个方法必须使用{} 并且不能带()。

必须使用{}原因:

使用{},是因为这里还是将函数赋值给onClick,不然会被解析为字符串。简单来说就是这里要使用js表达式了。

不能带()原因:这里就为了函数赋值给onClick回调,而不是将函数的返回值传递给onClick来回调

不然一渲染就会直接调用这个函数。而且onClick会回调函数的返回值,而不是函数本身。

6becbc62c6e5479eae8897a68a13c6f7_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


类中方法的this

  • babel开启严格模式

this是undefined

cb5c9f11159f48e68c1aa52478957cc9_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


77b7364e1c5b4522ab2fc869a24fe1d0_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 在render中的this就是组件实例对象,因为是组件实例对象调用的redner方法。
  • 使用外作用域定义变量取到组件实例对象的this

365a978a4b3d476986d5325ee7ca5ad3_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 将函数方法书写到类式组件中

5491ab6cf716441c97947224c5df880d_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • onClick不能直接调用方法(组件实例对象调用-添加this)

5b2ec4d7696643428f0157a901100a12_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


但是这里changeWeather方法中的this指向还是undefined


类中方法的this指向

<script type="text/javascript" >
        class Person {
                constructor(name,age){
                        this.name = name
                        this.age = age
                }
                study(){
                        //study方法放在了哪里?——类的原型对象上,供实例使用
                        //通过Person实例调用study时,study中的this就是Person实例
                        console.log(this);
                }
        }
        const p1 = new Person('tom',18)
        p1.study() //通过实例调用study方法
        const x = p1.study
        x() // 直接调用study
</script>
复制代码

ba293f7f8edc444d93a19d9b46cbff66_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 类中定义的所有方法,在局部作用域都开启了严格模式
  • 函数中开启严格模式

8a21b542523a4b3ead1dbffb34d3a910_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


c8e64c81ffd94d27a6ef58d2bdbe65d4_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • onClick是直接回调这个函数(不是组件实例对象调用的)

2bc037006a214e0b825d3e3c64c7fd7c_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 直接强行new一个类式组件的实例对象

dcd9dfc42382440a86538957afb9c48a_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


这里的this指向就是组件实例对象

d09e6c19746c406a8c0174a29c5268b7_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
  • 类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
<script type="text/babel">
        //1.创建组件
        class Weather extends React.Component{
                //构造器调用几次? ———— 1次
                constructor(props){
                        console.log('constructor');
                        super(props)
                        //初始化状态
                        this.state = {isHot:false,wind:'微风'}
                        //解决changeWeather中this指向问题
                        this.changeWeather = this.changeWeather.bind(this)
                }
                //render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数
                render(){
                        console.log('render');
                        //读取状态
                        const {isHot,wind} = this.state
                        return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
                }
                //changeWeather调用几次? ———— 点几次调几次
                changeWeather(){
                        //changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
                        console.log('changeWeather');
                        //获取原来的isHot值
                        const isHot = this.state.isHot
                        //严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
                        this.setState({isHot:!isHot})
                        console.log(this);
                        //严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!
                        //this.state.isHot = !isHot //这是错误的写法
                }
        }
        //2.渲染组件到页面
        ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
复制代码


解决类中this指向问题

使用bind

bind : 生成新函数、改变this指向

//解决changeWeather中this指向问题
this.changeWeather = this.changeWeather.bind(this)
复制代码


2ea79209320f4053a209111c45c51df9_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


解析过程:在组件对象的原型上找到函数,使用bind创建了一个一模一样的函数,但是讲函数的this修改为组件实例对象。并且将这个新函数作为一个值,赋值给了实例对象的一个叫changeWeather的方法。这样实例对象自身就会有一个changeWeather的方法。


注意:左边的changeWeather 在 实例对象身上、右边的changeWeather是原型对象上的。这段代码核心就是将原型对象上的方法加工改变this添加的实例对象上。

8f6b2de37a1e4476b3da9c0c10a6f959_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


对setState的使用

  • 对state对象的值修改必须使用setSate内置api(在React.component)

44db7770397849108153576a3b8e3f1f_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


console.log('changeWeather');
//获取原来的isHot值
const isHot = this.state.isHot
//严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
this.setState({isHot:!isHot})
console.log(this);
复制代码


  • 修改对象值是局部修改

严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。

  • 调用次数

构造器调用几次? ———— 1次(创建实现对象时调用)

render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数

changeWeather调用几次? ———— 点几次调几次


state的简写方式

核心解决手段来源:类中可以直接写赋值语句

class Car {
        constructor(name,price){
                this.name = name
                this.price = price
                // this.wheel = 4
        }
        //类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1
        a = 1
        wheel = 4
        static demo = 100
}
const c1 = new Car('奔驰c63',199)
const s1 = new Student('1','2');
复制代码


简写方法

  • 由于自定义函数太多了,大量使用bind。

将函数作为一个值直接赋值到一个属性上。

d07cb0bcb29049868b72bde210a5260d_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


e0f24125da664d6fab4e8d9f9d8daac9_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


注意: 还是会报错

bc409b8d9d144c2bbd76a9123c4777f3_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


解决方法,将function改为箭头函数模式

//自定义方法————要用赋值语句的形式+箭头函数
    changeWeather = ()=>{
        const isHot = this.state.isHot
        this.setState({isHot:!isHot})
    }
复制代码

原因:在箭头函数中,this引用的是定义箭头函数的上下文(红宝书p300)


  • 注意不允许这么写
changeWeather()=>{
    const isHot = this.state.isHot
    this.setState({isHot:!isHot})
}
复制代码


简写state

直接使用赋值语句

js

//初始化状态
state = {isHot:false,wind:'微风'}
复制代码


总结state

1. state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)

2. 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)


props的基本使用

传递组件属性

7b4afc1aba6c4a7393645721554eba24_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


4fb29004e278409c8b6aff6418b4947a_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


<script type="text/babel">
        //创建组件
        class Person extends React.Component{
                render(){
                        // console.log(this);
                        const {name,age,sex} = this.props
                        return (
                                <ul>
                                        <li>姓名:{name}</li>
                                        <li>性别:{sex}</li>
                                        <li>年龄:{age+1}</li>
                                </ul>
                        )
                }
        }
        //渲染组件到页面
        ReactDOM.render(<Person name="jerry" age={19}  sex="男"/>,document.getElementById('test1'))
        ReactDOM.render(<Person name="tom" age={18} sex="女"/>,document.getElementById('test2'))
        const p = {name:'老刘',age:18,sex:'女'}
        // console.log('@',...p);
        // ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
        ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
</script>
复制代码


批量传递props

展开运算符

传送门

developer.mozilla.org/zh-CN/docs/…

<script type="text/javascript" >
        let arr1 = [1,3,5,7,9]
        let arr2 = [2,4,6,8,10]
        console.log(...arr1); //展开一个数组
        let arr3 = [...arr1,...arr2]//连接数组
        //在函数中使用
        function sum(...numbers){
                return numbers.reduce((preValue,currentValue)=>{
                        return preValue + currentValue
                })
        }
        console.log(sum(1,2,3,4));
        //构造字面量对象时使用展开语法
        let person = {name:'tom',age:18}
        let person2 = {...person}
        //console.log(...person); //报错,展开运算符不能展开对象
        person.name = 'jerry'
        console.log(person2);
        console.log(person);
        //合并
        let person3 = {...person,name:'jack',address:"地球"}
        console.log(person3);
</script>
复制代码


批量传入props

react+babel 可以允许使用展开运算符展开对象。

  • 仅用于标签属性的传递


对props进行限制

对标签属性传递的类型进行限制

  • 在组件上添加propTypes属性

在React每次创建组件实例对象的时候就会访问组件本身的propTypes属性以便于限制props

  • 不同版本不同写法
//对标签属性进行类型、必要性的限制
Person.propTypes = {
        // 15版本
        name: React.PropTypes.string,
        // 16版本
        name:PropTypes.string.isRequired, //限制name必传,且为字符串
        sex:PropTypes.string,//限制sex为字符串
        age:PropTypes.number,//限制age为数值
        speak:PropTypes.func,//限制speak为函数,不使用function就是为了防止与关键字发生冲突
}
复制代码


16版本之后

<!-- 引入prop-types,用于对组件标签属性进行限制 -->
  <script type="text/javascript" src="../js/prop-types.js"></script>
复制代码

引入一个依赖包就产生一个全局对象,这里会产生一个propTypes全局对象。


属性默认值

//指定默认标签属性值
Person.defaultProps = {
        sex:'男',//sex默认值为男
        age:18 //age默认值为18
}
复制代码


props的简写方式

props是只读的

简写props

  • 将类似限制、默认值书写到类式组件内部

在类的原型上添加属性(使用static关键字)


类式组件中的构造器与props

  • 构造器传送门

zh-hans.reactjs.org/docs/react-…

-实际使用

0152869e29074dc6ab01feaad8be9685_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


161e4d50dcfb487f80bbfa246b97bd27_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


类中的构造器的作用

  • 如果不使用构造器接受props和使用super接受props,就无法使用实例对象访问props
constructor(props){
        //构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
        // console.log(props);
        super(props)
        console.log('constructor',this.props); // super constructor里面缺一个没传props参数都不可,否则就是undefined
}
复制代码


函数式组件使用props

函数式组件没有实例对象,但是可以接受参数

<script type="text/babel">
        //创建组件
        function Person (props){
                const {name,age,sex} = props
                return (
                                <ul>
                                        <li>姓名:{name}</li>
                                        <li>性别:{sex}</li>
                                        <li>年龄:{age}</li>
                                </ul>
                        )
        }
        //渲染组件到页面
        ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
</script>
复制代码


对props进行限制

  • 对组件添加属性
Person.propTypes = {
                name:PropTypes.string.isRequired, //限制name必传,且为字符串
                sex:PropTypes.string,//限制sex为字符串
                age:PropTypes.number,//限制age为数值
        }
        //指定默认标签属性值
        Person.defaultProps = {
                sex:'男',//sex默认值为男
                age:18 //age默认值为18
        }
复制代码


props总结

  • 理解

1. 每个组件对象都会有props(properties的简写)属性

2. 组件标签的所有属性都保存在props中

  • propsTypes

propsTypes是React要求的属性名,这个属性用来保存一个对象进而对props进行限制。

PropsTypes是使用prop-types库进限制(需要引入prop-types库)产生的全局对象


字符串形式的ref

  • 使用原生id属性事件绑定

ea43b47a41c74315895627ad9cc33a1b_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 使用ref标识
<input ref="input1" type="text" placeholder="点击按钮提示数据"/>&nbsp;
复制代码

2b755e08e7d0481eaadb653f79b07c12_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


//展示左侧输入框的数据
showData = ()=>{
        const {input1} = this.refs
        console.log(input1.value)
}
复制代码

946391ea34e54b41a6abc8f16baae52d_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


回调形式的ref

过时APl:String类型的Refs

传送门

zh-hans.reactjs.org/docs/refs-a…

  • 回调形式的ref
<input ref={c => this.input1 = c } type="text" placeholder="点击按钮提示数据"/>&nbsp;
复制代码


回调的箭头函数接收的参数正好就是ref属性所在的标签

a049e9ce3f3843e580cd0430e21aa5cf_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 上述代码的执行过程

在创建实例对象之后,实例对象调用render方法直接回调箭头函数。将作为参数的标签本身赋值到实例对象上的一个属性上。

这里就是将input标签赋值给实例对象的input属性上。


回调ref中调用次数的问题

传送门

zh-hans.reactjs.org/docs/refs-a…

35d03cb95c5443659aebeba073c4c389_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 第一次初始化渲染页面调用render

回调ref中调用1次

  • 更新过程

回调ref中调用2次本质:

1.初始化调用的回调函数已经被释放,状态更新后再次调用这个方法时就是一个新的方法。

2.由于不确定之前的函数接受到了什么,做了什么动作,为此就传入了null进行第一次调用。

3.在调用第二次的时候就传入了当前节点。

  • 实现结果

f5bfb7de042e4977b21037fdca3034d9_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • jsx注释方法
{/*<input ref={(c)=>{this.input1 = c;console.log('@',c);}} type="text"/><br/><br/>*/}
复制代码


  • 将 ref 的回调函数定义成 class 的绑定函数的方式
<script type="text/babel">
        //创建组件
        class Demo extends React.Component{
                state = {isHot:false}
                showInfo = ()=>{
                        const {input1} = this
                        alert(input1.value)
                }
                changeWeather = ()=>{
                        //获取原来的状态
                        const {isHot} = this.state
                        //更新状态
                        this.setState({isHot:!isHot})
                }
                saveInput = (c)=>{
                        this.input1 = c;
                        console.log('@',c);
                }
                render(){
                        const {isHot} = this.state
                        return(
                                <div>
                                        <h2>今天天气很{isHot ? '炎热':'凉爽'}</h2>
                                        {/*<input ref={(c)=>{this.input1 = c;console.log('@',c);}} type="text"/><br/><br/>*/}
                                        <input ref={this.saveInput} type="text"/><br/><br/>
                                        <button onClick={this.showInfo}>点我提示输入的数据</button>
                                        <button onClick={this.changeWeather}>点我切换天气</button>
                                </div>
                        )
                }
        }
        //渲染组件到页面
        ReactDOM.render(<Demo/>,document.getElementById('test'))
</script>
复制代码


createRef的使用

创建一个专属容器10515e1155714ef29f2d6ed34f0714e2_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 这里的myRef是一个对象,里面的current属性保存的是ref属性所在的标签

cac0993f68494ef48b70891ecfd739e0_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


总结 refs

  • 一共有4种方式使用refs


React中的事件处理

1. 通过onXxx属性指定事件处理函数(注意大小写)

1) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件---为了更好的兼容性
2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)---为了更高效
复制代码


2. 通过event.target得到发生事件的DOM元素对象 --- 避免过度使用ref

  • 事件委托(原理:事件冒泡)

所有的事件都添加到了最外层的标签上

这里就是div

210ae480298f4467b1b49a60b679b2ac_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


  • 避免过度使用ref

发生事件的元素正好就是要操作的元素。就可以使用event.target替代

//展示右侧输入框的数据
showData2 = (event)=>{
        alert(event.target.value);
}
<input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>&nbsp;



目录
相关文章
|
2月前
|
前端开发
React查询、搜索类功能的实现
React查询、搜索类功能的实现
16 0
|
3月前
|
前端开发 开发者 UED
【第33期】一文学会用React事件
【第33期】一文学会用React事件
21 0
|
3月前
|
存储 前端开发 JavaScript
【第29期】一文学会用React类组件编写组件
【第29期】一文学会用React类组件编写组件
30 0
|
7天前
|
前端开发 JavaScript
深入了解 React 中的 Ref:不是魔法,是超级工具
深入了解 React 中的 Ref:不是魔法,是超级工具
|
18天前
|
前端开发 JavaScript 开发者
如何在React中监听键盘事件
如何在React中监听键盘事件
26 0
|
2月前
|
前端开发 中间件 数据安全/隐私保护
React路由进阶方法
React路由进阶方法
25 1
|
2月前
|
前端开发 JavaScript Java
react事件机制
react事件机制
36 0
|
2月前
|
前端开发 JavaScript
快速上手React:从概述到组件与事件处理
快速上手React:从概述到组件与事件处理
|
3月前
|
前端开发
React 中条件渲染的 N 种方法
React 中条件渲染的 N 种方法
18 3
|
3月前
|
JavaScript 前端开发 Java
React 中的 ref 和 refs:解锁更多可能性(下)
React 中的 ref 和 refs:解锁更多可能性(下)
React 中的 ref 和 refs:解锁更多可能性(下)