首先提出需求,给input框绑定一个change事件,打印输入框中每次输入的内容。
在设定参数类型的时候,首先想到的就是Event
类型:
type IState = readonly<{ ... }> class Student extends React.Component<any, IState>{ inputChange = (e: Event) => { console.log(((e.target) as HTMLInputElement).value); } render(): React.ReactNode { return <div className="container"> <div className="box"> <input type="text" onChange={this.inputChange}/> </div> </div> } }
但是这样会报错:
不能将类型“(e: Event) => void”分配给类型“ChangeEventHandler<HTMLInputElement>”。 参数“e”和“event” 的类型不兼容。 类型“ChangeEvent<HTMLInputElement>”缺少类型“Event”的以下属性: cancelBubble, composed, returnValue, srcElement 及其他 7 项。ts(2322) index.d.ts(2254, 9): 所需类型来自属性 "onChange",在此处的 "DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>" 类型上声明该属性
从这个报错信息来看,onChange
事件需要的似乎是一个这样类型的处理函数ChangeEventHandler<HTMLInputElement>
现在先引入ChangeEventHandler
,看一看它对应的源码:
type ChangeEventHandler<T = Element> = EventHandler<ChangeEvent<T>>;
这意味着,我们的onChange
事件是一个EventHandler
,它自带的event
参数类型为ChangeEvent<T>
,由于这里是一个输入框,所以应该为event
设置参数为ChangeEvent<HTMLInputElement>
再来试试,成功获取到了输入内容!
type IState = readonly<{ ... }> class Student extends React.Component<any, IState>{ inputChange = (e: ChangeEvent<HTMLInputElement>) => { console.log((e.target.value)); } render(): React.ReactNode { return <div className="container"> <div className="box"> <input type="text" onChange={this.inputChange}/> </div> </div> } }
如果你使用的是hooks写法,也可以这样写,不过这并不是本节的重点:
inputChange = React.useCallback<React.ChangeEventHandler<HTMLInputElement>>((e) => { console.log((e.target.value)); },[])
接下来给扩展一个功能,如果有很多个输入框,是否可以共用同一个onChange
方法呢?
比如说,我现在需要多个输入框,分别输入学号、姓名、年龄的信息
如果分别给每个输入框绑定不同的事件,那就要写三个相似度非常高的函数,这样不太美观:
import React, { ChangeEvent } from 'react' type IState = Readonly<{ no: string, name: string, age: string }> class Student extends React.Component<any, IState>{ readonly state: IState = { no: "", name: "", age: "", list: [] } inputChangeNo = (key: string, e: ChangeEvent<HTMLInputElement>) => { // 不同的输入框触发change事件,最后打印的key值不同 console.log(key, e.target.value); } inputChangeName = (key: string, e: ChangeEvent<HTMLInputElement>) => { console.log(key, e.target.value); } inputChangeAge = (key: string, e: ChangeEvent<HTMLInputElement>) => { console.log(key, e.target.value); } render(): React.ReactNode { return <div className="container"> <div className="box"> <input type="text" value={this.state.no} onChange={(e) => this.inputChangeNo("no", e)} placeholder="输入学号" /> <input type="text" value={this.state.name} onChange={(e) => this.inputChangeName("name", e)} placeholder="输入姓名" /> <input type="text" value={this.state.age} onChange={(e) => this.inputChangeAge("age", e)} placeholder="输入年龄" /> </div> </div> } } export default Student
看起来我们似乎可以执行这样的操作:
inputChange = (key: string, e: ChangeEvent<HTMLInputElement>) => { this.setState({ [key]: e.target.value }) }
但是对于key
值来说,他是一个字符串索引类型数据,所以一定需要给他绑定对应的类型。
在这个案例中,我们需要用到的属性有:
type IState = Readonly<{ no: string, name: string, age: string, list: [] }>
所以索引对应的类型应该有 "no" | "name" | "age "
,成功设定!
import React, { ChangeEvent } from 'react' interface PeopleType{ id: number name: string age: string } interface IState{ [name: string]: string | PeopleType[] list: PeopleType[] no: string, name: string, age: string } class People extends React.Component<any, IState>{ readonly state: IState = { no: "", name: "", age: "", list: [] } inputChange = <K extends keyof IState>(key: K, e: ChangeEvent<HTMLInputElement>) => { this.setState({ [key]: e.target.value }) } render(): React.ReactNode { return <div className="container"> <div className="box"> <input type="text" value={this.state.no} onChange={(e) => this.inputChange("no", e)} placeholder="输入学号" /> <input type="text" value={this.state.name} onChange={(e) => this.inputChange("name", e)} placeholder="输入姓名" /> <input type="text" value={this.state.age} onChange={(e) => this.inputChange("age", e)} placeholder="输入年龄" /> </div> </div> } } export default People