使用 TypeScript 管理 React 中的用户事件
本教程将展示如何在 React 中使用 TypeScript 管理用户的事件,方法是在用户的操作上从一个组件到另一个组件传递一个 onClick
函数。
使用 TypeScript 在 React 中管理用户事件
我们将使用 create-react-app
快速启动和运行一个新的 React 项目。
npx create-react-app my-app --template typescript
cd my-app
npm run start
安装必要的包并启动开发服务器后,我们将转到 src/App.tsx
,删除所有样板代码并留下一个空组件。
import React from "react";
function Message() {
return <div></div>;
}
export default Message;
现在我们将在 div
添加一个用户可以单击的按钮,我们将通过在 onClick
属性中传递一个带有警报的函数来响应。
function Message() {
return (
<div>
<button
onClick={() => {
alert("I was clicked!");
}}>
Click Me!
</button>
</div>
);
}
从 Vanilla React 到 TypeScript 没有任何变化,但是一旦我们希望将 onClick
函数作为 Message
组件的 prop 传递,情况就不同了。为了展示这一点,我们将创建另一个名为 Game
的组件,它将 Message
作为其子组件。
function Game() {
return (
<div>
<Message></Message>
</div>
);
}
export default Game;
我们将使 Message
接收它的 onClick
功能和 text
作为来自 Game
的道具。
function Message({onClick, text}) {
return (
<div>
<button onClick={onClick}>{text}</button>
</div>
);
}
function Game() {
return (
<div>
<Message
onClick={() => {
alert("I was clicked!");
}}
text="Click me!"></Message>
</div>
);
}
但是,如果我们运行此代码,我们将得到以下编译错误。
Binding element 'onClick' implicitly has an 'any' type.
Binding element 'text' implicitly has an 'any' type.
在 Vanilla JavaScript 中,这不会导致错误,但 TypeScript 会抛出错误,因为 Message
的 onClick
和 text
道具隐含地具有 any
类型,即我们没有声明这些道具应该是哪种类型店铺。我们必须创建一个接口来指定 Message
的道具应该具有哪种类型来解决这个问题。
interface MessageProps {
text: string;
onClick: {};
}
text
属性应该具有的值很容易声明,因为它只是一个字符串。但是 onClick
的值更难。
onClick
不仅仅是一个常规函数,因为它具有 event
属性,并且它是 button
元素的预定属性。因此,要定义 onClick
,我们需要一个 React 附带的预定义接口,在本例中称为 ButtonHTMLAttributes
,它包含来自 button
元素的所有属性类型。
要使用它,我们必须扩展MessageProps
接口来存储 ButtonHTMLAttributes
类型。
interface MessageProps extends ButtonHTMLAttributes {
text: string;
}
然而,这还不够,运行这样的代码会抛出一个错误,因为 ButtonHTMLAttributes
接口是一个 Generic Type。你可以将泛型类型视为带有变量的接口,为了使用它们,我们在声明接口后将它们包裹在 <>
周围。
在这种情况下,ButtonHTMLAttributes
接口需要一个变量来知道我们正在使用哪个 HTML 元素,它将是全局的 HTMLButtonElement。
interface MessageProps extends ButtonHTMLAttributes<HTMLButtonElement> {
text: string;
}
MessageProps
不仅包含 text
和 onClick
道具的类型,还包含 button
元素的所有道具的类型。你可以将 button
中的任何道具添加到 Message
。
如果你只想扩展 onClick
属性,不要扩展界面,创建一个新的 onClick
类型并使用索引访问类型分配 ButtonHTMLAttributes
的 onClick
属性。
interface MessageProps {
text: string;
onClick: ButtonHTMLAttributes<HTMLButtonElement>["onClick"];
}
最后,我们必须声明 Message
组件将通过以下方式将 MessageProps
用于其 props。
function Message({onClick, text}: MessageProps) {
return (
<div>
<button onClick={onClick}>{text}</button>
</div>
);
}
如果我们愿意,我们可以将返回类型注释为 JSX.Element
,这样如果我们不小心返回了其他类型,TypeScript 就会抛出错误。
function Message({onClick, text}: MessageProps): JSX.Element {
return (
<div>
<button onClick={onClick}>{text}</button>
</div>
);
}
这将是最终的结果。
import React from "react";
import {ButtonHTMLAttributes} from "react";
interface MessageProps {
text: string;
onClick: ButtonHTMLAttributes<HTMLButtonElement>["onClick"];
}
function Message({onClick, text}: MessageProps): JSX.Element {
return (
<div>
<button onClick={onClick}>{text}</button>
</div>
);
}
function Game() {
return (
<div>
<Message
onClick={() => {
alert("I was clicked!");
}}
text="Click me!"></Message>
</div>
);
}
export default Game;
Juan Diego Rodríguez (also known as Monknow) is a front-end developer from Venezuela who loves to stay updated with the latest web development trends, making beautiful websites with modern technologies. But also enjoys old-school development and likes building layouts with vanilla HTML and CSS to relax.
LinkedIn