[React 基础系列] 事件处理
Posted GoldenaArcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[React 基础系列] 事件处理相关的知识,希望对你有一定的参考价值。
[React 基础系列] 事件处理
在 状态 & 状态更新 & 生命周期方法 中曾经简略的提到了在 onChange 这个事件处理机制中更新状态,本篇更加相近地讲一下在我过去开发中碰到使用比较多的事件,以及一些常用的处理事件的方法和经验。
之前复习过的内容有:
这部分的学习资源在 [React 基础系列] 事件处理-案例
事件处理基础
React 的事件处理核心逻辑与传统的 javascript 还是一样的,都是通过回调函数去执行,假设 JavaScript 的 点击事件处理函数(onclickHandler) 都已经实现好了:
const onclickHandler = () => {
console.log('button clicked');
};
在 html 中的调用是这么实现的:
<button onclick="onclickHandler()">btn</button>
React 中的实现和在 HTML 中的实现就有些不太一样了,以类组件为例:
class Input extends Component {
// 类组件声明函数是不需要 const 关键字的
onclickHandler = () => {
console.log('button clicked');
};
render() {
// 注意 onClick 的大小写问题,以及引用是不带括号的
return <button onClick={this.onclickHandler}>submit</button>;
}
}
这里使用箭头函数是因为箭头函数里面不存在 this
的指向问题,注意这里并没有直接调用 this.onclickHandler
,React 内部有其他的处理机制去调用 this.onclickHandler
,所以如果是用传统的函数式写法,就会出现 this
指向 出错问题:
class Input extends Component {
onclickHandler() {
console.log('button clicked');
}
}
在调用 this
的时候就会引发下列报错:
所以,如果是用传统的函数式写法,就需要在构造函数中使用 bind
去绑定 this
的指向:
class Input extends Component {
constructor(props) {
super(props);
this.onclickHandler = this.onclickHandler.bind(this);
}
}
this
的指向和 bind
的用法属于 JavaScript 的通用问题,并不只是针对 React 的类组件而实行的。在处理任何的组件以及较为复杂的 JavaScript 逻辑时,都需要注意 this
的指向问题。
简单的总结一下,主要的差别有 2 个:
- 引用的函数不包含小括号
()
- React 中为了防止关键字冲突所以有
onclick
与onClick
的区别
另外一个需要注意的点就是 this
的指向问题和 bind
的使用。关于什么时候使用箭头函数去处理事件,什么时候使用 bind
去绑定函数,根据官网的这番话:
此语法(在回调函数中使用箭头函数,语法为:
{() => this.handleClick()}
) 问题在于每次渲染 LoggingButton 时都会创建不同的回调函数。在大多数情况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题。
就可以理解为说,如果当前的事件处理只需要在本组件内被调用,不需要传给其他的组建去处理,使用箭头函数是没有问题的;但是,如果函数需要被作为 props 传给其他的组件,那么就需要使用 bind
去确认 this
的指向问题。
常用的事件处理方法
React 封装的时间处理方法还挺多的,完整的 API 可以参考 SyntheticEvent 这里查看所有支持的事件,这里只是就经验列举几个之前开发过程中比较常用的事件。
鼠标事件 - onClick
onClick 的使用就像上半部分使用的案例一样,一般来说使用 onClick 的场景主要在:
-
页面重定向
如有些页面会有的不同按钮,上一页、下一页、返回,都在 onClick 中进行事件处理
-
API 调用
这种更多的在搜索功能、提交表单使用。
提交表单真的要根据业务实现的方式了,有使用 onClick 实现的,也有使用 onSubmit 实现的。
-
radio/checkbox 选中后更新状态
-
a 标签的处理
这时候要特别注意
preventDefault()
调用的问题,React 中要阻止默认行为——如 a 标签默认会打开新的页面或者重定向这种情况,就必须要调用e.preventDefault();
去阻止默认行为。当然,React 其实也建议,如果不需要页面的重定向,其实可以不用 a 标签,而是使用 span 搭配 CSS 进行实现。
聚焦事件
聚焦事件总共有两个,一个是 onFocus(聚焦时被调用),一个是 onBlur(失去焦点时会被调用)。
其中 onFocus 使用的场景比较少,用的更多的是 onBlur,在表单内容失去聚焦的时候对其进行验证,如果数据有问题就直接清空,下面是简单的案例:
class Input extends Component {
blurEvent = () => {
console.log(this.state.input, 'onblur');
// 如果电话号码不是11位就自动清空
if (this.state.input.length !== 11) {
this.setState({
input: '',
});
}
};
render() {
return (
<div>
<div>
<label>{this.props.label}</label>
<input
type="text"
value={this.state.input}
onChange={(e) => this.updateInputHandler(e)}
onBlur={this.blurEvent}
/>
</div>
<button onClick={this.onclickHandler}>submit</button>
</div>
);
}
}
效果如下:
可以看到,在 onBlur 中的 this.setState
触发之后,也会触发 componentDidUpdate,所以当页面逻辑比较复杂的情况下,一定要注意 componentDidUpdate 的实现,避免进入无限死循环的状态。
表单事件 - onChange
上一篇 状态 & 状态更新 & 生命周期方法 中已经实现了 onChange 方法,不过使用的是在箭头函数中调用箭头函数的方法:onChange={(e) => this.updateInputHandler(e)}
。
这里更新为使用 bind 的方法进行重写:
class Input extends Component {
constructor(props) {
// 也必须要调用 super(props)
super(props);
this.state = { input: '13001301300' };
// 添加 bind 事件
this.updateInputHandler = this.updateInputHandler.bind(this);
}
// 函数的实现方法不需要改变
render() {
return (
<div>
<label>{this.props.label}</label>
<input
type="text"
value={this.state.input}
// 原本的 onChange 调用被注释了
// onChange={(e) => this.updateInputHandler(e)}
onChange={this.updateInputHandler}
onBlur={this.blurEvent}
/>
</div>
);
}
}
这个实现方式还是比较建议去做的,尤其是表单的 input, radio, checkbox 这种组件其实可以被单独拉出来拆分的情况下,就需要将时间处理函数作为 props 传到子组件里。页面上的表单内容多了的情况下,确实需要考虑一下业务的优化问题。
总结
这章学习了一下事件处理方法,着重讲了三种不同的事件处理分类:
- HTML 中的事件处理
- React 中不需要传参数的事件处理
- React 中需要传参数的事件处理
对于 2 和 3 点,也分别使用了不同的实例事件:onClick, onChange, onBlur 进行学习。
其他的事件基本可以参照这三个较为常用的事件去进行事件,毕竟 React 对于方法的封装和实现都是基于同一套理念,也必然会在内部进行封装。故此,函数的实现及调用方法也是差不多的。
以上是关于[React 基础系列] 事件处理的主要内容,如果未能解决你的问题,请参考以下文章