[React 基础系列] 事件处理

Posted GoldenaArcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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 个:

  1. 引用的函数不包含小括号()
  2. React 中为了防止关键字冲突所以有 onclickonClick 的区别

另外一个需要注意的点就是 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 传到子组件里。页面上的表单内容多了的情况下,确实需要考虑一下业务的优化问题。

总结

这章学习了一下事件处理方法,着重讲了三种不同的事件处理分类:

  1. HTML 中的事件处理
  2. React 中不需要传参数的事件处理
  3. React 中需要传参数的事件处理

对于 2 和 3 点,也分别使用了不同的实例事件:onClick, onChange, onBlur 进行学习。

其他的事件基本可以参照这三个较为常用的事件去进行事件,毕竟 React 对于方法的封装和实现都是基于同一套理念,也必然会在内部进行封装。故此,函数的实现及调用方法也是差不多的。

以上是关于[React 基础系列] 事件处理的主要内容,如果未能解决你的问题,请参考以下文章

React 系列导航

Reactreact概述组件事件

React组件基础

React组件基础

[vscode]--HTML代码片段(基础版,reactvuejquery)

Vue基础系列事件处理-常用事件修饰符