概述
我们知道React中处理事件有以下两种方式
- 内联匿名函数
- 单独定义事件处理函数
在不考虑性能的情况下可以使用内联函数来处理事件,因为每次render组件,如果使用内联函数,在组件上绑定的事件都会新建一个匿名函数的实例,影响性能。我们这篇文章讨论表单事件,当然普通的div事件类似,我们以input的onChange事件为例,来分析下在Ts中这两种绑定事件的方式。
内联函数方式处理事件
const btn = (<inputonChange={event => {/* ... */}}/>);
以上我们定义了一个变量名为btn的button组件,onClick事件我们使用了内联的形式,在Ts中,该事件的参数和返回值,都只能通过上下文来推断出来的,相反,我们要是单独定义事件处理函数,因为@type(搭建支持TS语言的React项目时候会安装)包给我们定义了大量的类型,所以IDE会给我们很多的提示,下面看看单独的事件处理程序的写法,如下
单独定义事件处理函数
import React from 'react';class HelloWorld extends React.Component<{}, { text: string }> {state = {text: '',};onChange = (e: React.FormEvent<HTMLInputElement>): void => {this.setState({text: e.currentTarget.value,});};render() {return (<div><input onChange={this.onChange}></input><div>{this.state.text}</div></div>);}}export default HelloWorld;
看看上面的代码我们将input的onChange事件绑定了一个外部编写的onChange函数上,我们指定事件函数的参数event为React.FormEvent
事件处理函数的EventHandler类型
回顾下我们上面写的onChange类型函数,如下
onChange = (e: React.FormEvent<HTMLInputElement>): void => {this.setState({text: e.currentTarget.value,});};
我们分别定义了参数类型为React.FormEvent<>和返回值类型为void,其实我们可以用另外一种方式来替换这种写法,我们直接给事件处理函数一个类型就OK了。我们可以使用@types/react 提供的EventHandler来声明事件处理函数,我们首先将上面的函数用ChangeEventHandler类型重写一下如下、
onChange: React.ChangeEventHandler<HTMLInputElement> = e => {this.setState({text: e.currentTarget.value,});};
我们选择了一个ChangeEventHandler类型来约束input的onChange事件,这样子在函数体也就有了对应的调用提示,下面我们来看看这个ChangeEventHandler是个什么东西,和都有什么类型的EventHandler我们可以用,我们点击ChangeEventHandler类型到声明类型的文件中如下;
我们可以看到@types/react定义了很多的XxxEventHandler来处理不同的事件,其实很简单,每个类型都是调用了第一行的EventHanlder函数类型,该类型就是返回了函数名为“bivarianceHack”的函数类型,(event:E)=>void,这个正如咱们上面所说的一样,这下就知道了为何这种方式可以取代分别声明参数类型和返回值类型的方式了吧。继续看,EventHandler的范型要求是继承SyntheticEvent的范型,看红框里面的方法调用,这些参数都是继承了SyntheticEvent,不同的范型定义了不同事件对应事件对象的Event的约束参数。这里的event类型就是我们内联函数中说到的那些event类型。我们找一个MouseEvent的定义来看一下吧
可以看到MouseEvent里面定义一下和鼠标点击时候的位置相关的一些参数。
有了这些EventHandler我们就可以很方便的编写事件函数的类型了。
