【React】事件处理基本用法、受控组件 非受控组件


1. 事件处理

React事件处理与DOM事件处理的区别:

1、在语法上的不同点:

  • React中事件的命名采用驼峰命名法。
  • 响应事件的函数要以对象的形式赋值。
DOM方式
 <button οnclick=“clickMe”>点我</button>
React方式
<button onClick={clickButton}>不服点我</button>  
//clickButton是一个函数

2、在阻止事件的默认行为有区别: React事件是合成的,DOM事件是原生

  • DOM:返回false阻止默认事件
  • React:显示调用事件对象e.preventDefault来阻止事件的默认行为。

在React中获取虚拟组件中的标签的值:

  1. 使用组件的refs属性
  2. 在虚拟组件的标签中定义事件,在事件中通过箭头函数获取标签的值
  3. 使用事件对象:event

1.1 事件处理函数

1.1.1 使用ES6的箭头函数

class MyComponent extends React.Component{
    constructor(props){
        super(props);
        this.state={
            number:0
        }
    handleClick=()=>{
        ++this.state.number;
        console.log(this.state.number);
    }
    render(){
        return(
            <div>
                <button type='button' onClick={this.handleClick}>点我</button>  
            </div>
        )
    }
}
ReactDOM.render(<MyComponent/>,document.getElementById('example'));

当前this指向的是当前组件的实例。

不足:当组件的逻辑比较复杂时,把组件的逻辑写在{ }内会导致render()函数变得臃肿,不能比较直观的看出ui结构,代码可读性不好。

1.1.2 在组件中定义事件处理函数

class MyComponent extends React.Component{
    constructor(props){
        super(props);
        this.state={
            number:0
        }
        this.handleClick=this.handleClick.bind(this);
    }
    handleClick(){
        ++this.state.number;
        console.log(this.state.number);
    }
    render(){
        return(
            <div>
                <button type='button' onClick={this.handleClick}>点我</button>  
            </div>
        )
    }
}
ReactDOM.render(<MyComponent/>,document.getElementById('example'));

这种方法的好处是每次render渲染都不会重新创建一个回调函数,没有额外的性能损失。

但是如果在一个组件中有很多的事件函数时这种在构造函数中绑定this的方法会显得繁琐.

1.1.3 在给事件赋值时绑定this

class MyComponent extends React.Component{
    constructor(props){
        super(props);
        this.state={
            number:0
        }
    }
    handleClick(){
        ++this.state.number;
        console.log(this.state.number);
    }
    render(){
        return(
            <div>
                <button type='button' onClick={this.handleClick.bind(this)}>点我</button>     
            </div>
        )
    }
}
ReactDOM.render(<MyComponent/>,document.getElementById('example'));

但是此方法在每次render时都会重新创建一个新的函数,性能有一定的损失。

但在事件处理函数需要传参数时,这种方法就比较好。

1.2 事件流

在该示例中,3个div嵌套显示,并且每个元素上均绑定onClick事件。当用户点击红色区域的div元素时,可以看到,控制台先后输出了child -> parent -> ancestor,这是因为在React的事件处理系统中,默认的事件流就是冒泡。

const style={
    child:{
        width:'100px',
        height:'100px',
        background:'red'
    },
    parent:{
        width:'150px',
        height:'150px',
        background:'blue'
    },
    ancestor:{
        width:'200px',
        height:'200px',
        background:'green'
    }
}

class Example extends React.Component{
    render(){
        return(
            <div onClick={()=> console.log('ancestor')} style={style.ancestor}>
                <div onClick={ ()=> console.log('parent')} style={style.parent}>
                    <div onClick={ ()=> console.log('child')} style={style.child}></div>    
                </div>
            </div>
        )
    }
}

ReactDOM.render(<Example/>,document.getElementById('example'));  

在这里插入图片描述

  • React默认的事件触发方式:冒泡方式
  • 若将事件触发改为捕获方式:需要在事件名后带上Capture后缀
<div onClickCapture={()=> console.log('ancestor')} style={style.ancestor}>
	<div onClickCapture={ ()=> console.log('parent')} style={style.parent}>
		<div onClickCapture={ ()=> console.log('child')} style={style.child}></div>
	</div>
</div>

1.3 事件委托

在合成事件系统中,所有的事件都是绑定在document元素上。即:虽然我们在某个react元素上绑定了事件,但是,最后事件都委托给document统一触发。
在这里插入图片描述

在合成事件中只能阻止合成事件中的事件传播。

eg:点击红色div,可以看到控制台上只输出了child,说明这时已经成功阻止了冒泡。

<div id='example'></div>


<script type="text/babel">
    const style={
        child:{
            width:'100px',
            height:'100px',
            background:'red'
        },
        parent:{
            width:'150px',
            height:'150px',
            background:'blue'
        },
        ancestor:{
            width:'200px',
            height:'200px',
            background:'green'
        }
    }

    class Example extends React.Component{
        render(){
            return(
                <div onClick={()=> console.log('ancestor')} style={style.ancestor}>
                    <div onClick={ ()=> console.log('parent')} style={style.parent}>
                        <div onClick={ (e)=> {
                            console.log('child');
                            e.stopPropagation();
                        }} style={style.child}></div>    
                    </div>
                </div>
            )
        }
    }

	ReactDOM.render(<Example/>,document.getElementById('example'));  
</script>

在这里插入图片描述
执行流程如下:
在这里插入图片描述

React 阻止的事件流,并没有阻止真正DOM元素的事件触发,还是按照冒泡的方式,层层将事件交给上级元素进行处理,最后事件传播到docuement,触发合成事件。
在合成事件中,child触发时,e.stopPropagation()被调用,合成事件中的事件被终止。
因此,合成事件中的stopPropagation无法阻止事件在真正元素上的传递,它只阻止合成事件中的事件流。
相反,如果绑定一个真正的事件,那么,合成事件则会被终止。

1.4 事件对象

在合成事件中,依然可以获取到事件发生时的event对象

eg:

<div id='example'></div>

<script type="text/babel">

    const style = {
        div:{
            width:'200px',
            height:'200px',
            background:'red'
        },
    }
    
    class App extends React.Component{
        state = {
            x: 0,
            y: 0
        }

        render() {
            return (
                <div>
                    <div style={style.div}
                        onClick = {
                            e => {
                                this.setState({
                                    x: e.clientX,
                                    y: e.clientY
                                })
                            }
                        }
                    >
                        x: {this.state.x},y : {this.state.y}
                    </div>
                </div>
            )
        }
    }


    ReactDOM.render(<App/>,document.getElementById('example'));  
</script>

在这里插入图片描述

合成事件中的event对象,并不是原生的event,只是说,我们可以通过它获取到原生event对象上的某些属性。
比如以上示例中的clientX和clientY。
而且,对于这个event对象,在整个合成事件中,只有一个,被全局共享,也就是说,当这次事件调用完成之后,这个event对象会被清空,等待下一次的事件触发,因此,我们无法在异步的操作中获取到event。

在这里插入图片描述

2. 受控组件、非受控组件

2.1 受控组件

在HTML中,标签<input><textarea><select>的值的改变通常是根据用户输入进行更新。
在React中,可变状态通常保存在组件的状态属性中,并且只能使用setState()更新,而呈现表单的React组件也控制着在后续用户输入时该表单中发生的情况,以这种由React控制的输入表单元素而改变其值的方式,称为:“受控组件”。

eg:点击登录输出用户的输入的用户名和密码

import React,{Compontent} from 'react';

class Mydemo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {name: ''};
        this.handleNameChange = this.handleNameChange.bind(this);
    }

    handleNameChange(event) {
        this.setState({ name: event.target.value });
    };

    render() {
        return (
            <div>
                <input type="text" value={this.state.name} onChange={this.handleNameChange}/>
                <br/> name : {this.state.name}
            </div>
        );
    }
}

export default Mydemo;

在这里插入图片描述

  • name开始是空字符串''
  • 当键入a,并handleNameChange获取a和调用setState。然后,该输入被重新呈现为具有的值a。
  • 当继续键入bhandleNameChange获取ab并设置该状态的值。现在再次重新渲染输入value="ab"

这也意味着表单组件可以立即响应输入更改。

受控执行情况:

元素属性方法方法回调中的新值
<input type='text'/>value=‘string’onChangeevent.target.value
<input type='checxbox'/>checked={boolean}onChangeevent.target.checked
<input type='radio'/>checked={boolean}onChangeevent.target.checked
<textarea>value=‘string’onChangeevent.target.value
<select>value=‘option value’onChangeevent.target.value

可见效果:

  • 当注释this.setState({value: event.target.value}); 这行代码,文本框再次输入时,页面不会重新渲染,所产生效果即是文本框输入不了值,即文本框值的改变受到setState()方法的控制,在未执行时,不重新渲染组件。

2.2 非受控组件

表单数据由DOM本身处理。即不受setState()的控制,与传统的HTML表单输入相似,input输入值即显示最新值(使用 ref从DOM获取表单值)

import React,{Compontent} from 'react';

class Mydemo extends React.Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleSubmit(event) {
        alert('A name was submitted: ' + this.input.value);
        event.preventDefault();
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    Name:
                    <input type="text" ref={(input) => this.input = input} />
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}

export default Mydemo;

在这里插入图片描述
受控和非受控元素都有其优点,根据具体情况选择
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南栀~zmt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值