React 组件中的事件处理、组件(受控、非受控)、函数柯里化

事件处理

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

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

事件处理:

  • 通过onXxx属性指定事件处理函数(注意大小写)
    • React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 ———为了更好的兼容性
    • React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————为了高效
  • 通过event.target得到发生事件的DOM元素对象 ———不要过度使用ref

使用event.target属性:

//创建组件
class Demo extends React.Component{
    myRef = React.createRef()
    //展示输入框的数据
    showData = (event)=>{
        alert(event.target.value);
    }

    render(){
        return(
            <div>
                <input onBlur={this.showData} type="text" placeholder="失去焦点提示数据"/>
            </div>
        )
    }
}
//渲染组件到页面
ReactDOM.render(<Demo/>,document.getElementById('test'))

React事件处理和Dom事件处理区别:

1、在 语法 上的不同点:

  • React事件名采用驼峰命名法,即事件名首字母大写。如onclick(Dom)——onClick(React)

  • 响应事件的函数在React中以 对象方式 赋值,Dom是以 字符串方式 赋值

    <button onclick= ' clickMe( ) '>提交</button>  ——Dom方式
    <button onClick={ clickMe( ) }>提交</button> ——React方式
    

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

  • Dom:返回false
  • React:显示的调用事件对象event.preventDefault

React事件处理函数

  • 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'));
    
  • 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的方法会显得繁琐
  • 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时都会重新创建一个新的函数,性能有一定的损失,但在事件处理函数需要传参数时,这种方法就比较好

事件流

在该示例中,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 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>
        )
    }
}

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>

事件委托

在合成事件系统中,所有的事件都是绑定在document元素上,即虽然在某个React元素上绑定了事件,但是,最后事件都委托给document统一触发。因此,在合成事件中只能阻止合成事件中的事件传播

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

  • 默认事件流是冒泡的,所有事件统一由document触发,在React中阻止冒泡方法是调用e.stopPropagation()
  • React的合成事件是可以找到原生的事件对象
  • React中的合成事件中只有一个全局对象event,该对象不是原生的event,但通过它可以获得event对象的部分属性。每个事件触发完后React的全局对象event就会被清空,因此不能在异步操作使用

事件类型:
在这里插入图片描述

收集表单数据

非受控组件

表单数据由DOM本身处理。即不受setState()的控制,与传统的HTML表单输入相似,input输入值即显示最新值(使用 ref 从DOM获取表单值),即不受React控制改变表单元素提交的值的方式,称为:“非受控组件”

class Login extends React.Component{
    handleSubmit = (event)=>{
        event.preventDefault() //阻止表单提交
        const {username,password} = this
        alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`)
    }
    render(){
        return(
            <form onSubmit={this.handleSubmit}>
                用户名:<input ref={c => this.username = c} type="text" name="username"/>
                密码:<input ref={c => this.password = c} type="password" name="password"/>
                <button>登录</button>
            </form>
        )
    }
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))

受控组件

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

class Login extends React.Component{
    //初始化状态
    state = {
        username:'', //用户名
        password:'' //密码
    }
    //保存用户名到状态中
    saveUsername = (event)=>{
        this.setState({username:event.target.value})
    }
    //保存密码到状态中
    savePassword = (event)=>{
        this.setState({password:event.target.value})
    }
    //表单提交的回调
    handleSubmit = (event)=>{
        event.preventDefault() //阻止表单提交
        const {username,password} = this.state
        alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
    }
    render(){
        return(
            <form onSubmit={this.handleSubmit}>
                用户名:<input onChange={this.saveUsername} type="text" name="username"/>
                密码:<input onChange={this.savePassword} type="password" name="password"/>
                <button>登录</button>
            </form>
        )
    }
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))

受控和非受控元素都有其优点,根据具体情况选择

特征非受控制受控
一次性检索(例如表单提交)
及时验证×
有条件的禁用提交按钮×
执行输入格式×
一个数据的几个输入×
动态输入×

函数柯里化

高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。

  1. 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数
  2. 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数

常见的高阶函数有:Promise、setTimeout、arr.map()等等

函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

function sum(a){
		return(b)=>{
			return (c)=>{
				return a+b+c
				}
		}
}

函数柯里化的实现

class Login extends React.Component{
    //初始化状态
    state = {
        username:'', //用户名
        password:'' //密码
    }
    //保存表单数据到状态中
    saveFormData = (dataType)=>{
        return (event)=>{
            this.setState({[dataType]:event.target.value})
        }
    }
    //表单提交的回调
    handleSubmit = (event)=>{
        event.preventDefault() //阻止表单提交
        const {username,password} = this.state
        alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
    }
    render(){
        return(
            <form onSubmit={this.handleSubmit}>
                用户名:<input onChange={this.saveFormData('username')} type="text" name="username"/>
                密码:<input onChange={this.saveFormData('password')} type="password" name="password"/>
                <button>登录</button>
            </form>
        )
    }
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))

不用柯里化的实现

class Login extends React.Component{
    //初始化状态
    state = {
        username:'', //用户名
        password:'' //密码
    }
    //保存表单数据到状态中
    saveFormData = (dataType,event)=>{
        this.setState({[dataType]:event.target.value})
    }
    //表单提交的回调
    handleSubmit = (event)=>{
        event.preventDefault() //阻止表单提交
        const {username,password} = this.state
        alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
    }
    render(){
        return(
            <form onSubmit={this.handleSubmit}>
                用户名:<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>
                密码:<input onChange={event => this.saveFormData('password',event) } type="password" name="password"/>
                <button>登录</button>
            </form>
        )
    }
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值