作者选择Creative Commons接受捐赠,作为Write for DOnations计划的一部分。
介绍
在 Web 开发中,事件代表 Web 浏览器中发生的操作。通过使用事件处理程序响应事件,您可以创建响应任何用户操作的动态JavaScript应用程序,包括使用鼠标单击、沿网页滚动、触摸触摸屏等。
在React应用程序中,您可以使用事件处理程序来更新状态数据、触发属性更改或阻止默认浏览器操作。为此,React 使用SyntheticEvent
包装器而不是本机Event
接口。SyntheticEvent
密切模拟标准浏览器事件,但为不同的 Web 浏览器提供更一致的行为。Window
当组件从文档对象模型 (DOM)挂载和卸载时,React 还为您提供了安全添加和删除事件侦听器的工具,让您可以控制Window
事件,同时防止因不正确删除侦听器而导致内存泄漏。
在本教程中,您将学习如何在 React 中处理事件。您将构建几个处理用户事件的示例组件,包括一个自我验证的输入组件和一个用于输入表单的信息工具提示。在整个教程中,您将学习如何向组件添加事件处理程序、从 中提取信息SyntheticEvent
以及添加和删除Window
事件侦听器。在本教程结束时,您将能够使用各种事件处理程序并应用React 支持的事件目录。
先决条件
-
你需要一个运行Node.js的开发环境;本教程在 Node.js 版本 10.22.0 和 npm 版本 6.14.6 上进行了测试。要在 macOS 或 Ubuntu 18.04 上安装它,请按照如何在 macOS 上安装 Node.js 和创建本地开发环境或如何在 Ubuntu 18.04 上安装 Node.js 的使用 PPA 安装部分中的步骤进行操作。
-
使用Create React App设置的 React 开发环境,删除了非必要的样板。要进行设置,请按照如何管理 React 类组件上的状态教程的第 1 步 – 创建一个空项目。本教程将
events-tutorial
用作项目名称。 -
您还需要具备 JavaScript 和 HTML 的基本知识,您可以在我们的如何使用 HTML 构建网站系列和如何在 JavaScript 中编码中找到这些知识。CSS 的基本知识也很有用,您可以在Mozilla 开发人员网络找到这些知识。
-
您将使用 React 组件、
useState
Hook 和useReducer
Hook,您可以在我们的教程如何在 React 中创建自定义组件和如何在 React 组件上使用钩子管理状态中了解这些内容。
第 1 步 – 提取事件数据 SyntheticEvent
在此步骤中,您将使用<input>
HTML 元素和onChange
事件处理程序创建验证组件。该组件将接受输入并对其进行验证,或确保内容符合特定的文本模式。您将使用SyntheticEvent
包装器将事件数据传递到回调函数中,并使用<input>
. 您还将从调用函数SyntheticEvent
,例如preventDefault
阻止标准浏览器操作。
在 React 中,您不需要在添加事件侦听器之前选择元素。相反,您可以使用 props将事件处理程序直接添加到JSX。React中有大量支持的事件,包括诸如onClick
或 之类的onChange
常见事件和诸如onWheel
.
与原生DOMonevent
处理程序不同,React 传递一个特殊的包装器,调用SyntheticEvent
事件处理程序而不是原生浏览器Event
。抽象有助于减少跨浏览器的不一致,并为您的组件提供处理事件的标准接口。的 APISyntheticEvent
类似于本机Event
,因此大多数任务都以相同的方式完成。
为了证明这一点,您将首先进行验证输入。首先,您将创建一个名为FileNamer
. 这将是一个<form>
带有用于命名文件的输入的元素。当您填写输入时,您将看到信息更新组件上方的预览框。该组件还将包含一个用于运行验证的提交按钮,但对于此示例,表单实际上不会提交任何内容。
首先,创建目录:
- mkdir src/components/FileNamer
然后FileNamer.js
在你的文本编辑器中打开:
- nano src/components/FileNamer/FileNamer.js
在里面FileNamer.js
,创建一个 wrapper <div>
,然后通过编写以下代码行添加另一个<div>
类名为preview
和<form>
元素的包装器:
import React from 'react';
export default function FileNamer() {
return(
<div className="wrapper">
<div className="preview">
</div>
<form>
</form>
</div>
)
}
接下来,为要在预览框中显示的名称添加一个输入元素和一个保存按钮。添加以下突出显示的行:
import React from 'react';
export default function FileNamer() {
return(
<div className="wrapper">
<div className="preview">
<h2>Preview:</h2>
</div>
<form>
<label>
<p>Name:</p>
<input name="name" />
</label>
<div>
<button>Save</button>
</div>
</form>
</div>
)
}
在 中preview
<div>
,您添加了一个<h2>
带有文本的元素Preview
。这将是您的预览框。在您的表单中,您添加了一个<input>
被<label>
元素包围的Name:
文本。然后您在结束标记之前直接添加了一个button
名为Save的<form>
代码。
保存并关闭文件。
接下来,打开App.js
:
- nano src/components/App/App.js
导入FileNamer
,然后App
通过添加以下突出显示的行在函数内部进行渲染:
import React from 'react';
import FileNamer from '../FileNamer/FileNamer';
function App() {
return <FileNamer />
}
export default App;
保存并关闭文件。当您这样做时,浏览器将刷新,您将看到您的组件。
接下来,添加一些浅色样式以帮助定义部分并为元素添加一些填充和边距。
FileNamer.css
在文本编辑器中打开:
- nano src/components/FileNamer/FileNamer.css
给.preview
类一个灰色的边框和填充,然后给这个.wrapper
类少量的填充。使用flex
和显示列中的项目flex-direction
,并使所有文本左对齐。最后,通过移除边框并添加黑色边框来移除默认按钮样式:
.preview {
border: 1px darkgray solid;
padding: 10px;
}
.wrapper {
display: flex;
flex-direction: column;
padding: 20px;
text-align: left;
}
.wrapper button {
background: none;
border: 1px black solid;
margin-top: 10px;
}
保存并关闭文件。然后打开FileNamer.js
:
- nano src/components/FileNamer/FileNamer.js
导入样式以将它们应用于您的组件:
import React from 'react';
import './FileNamer.css';
export default function FileNamer() {
return(
<div className="wrapper">
<div className="preview">
<h2>Preview:</h2>
</div>
<form>
<label>
<p>Name:</p>
<input name="name" />
</label>
<div>
<button>Save</button>
</div>
</form>
</div>
)
}
保存文件。当您这样做时,浏览器将刷新并且您会发现该组件具有新样式。
现在您有了一个基本组件,您可以向<input>
元素添加事件处理程序。但首先,您需要一个地方来存储输入字段中的数据。添加useState
Hook以保存输入:
import React, { useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
const [name, setName] = useState('');
return(
<div className="wrapper">
<div className="preview">
<h2>Preview: {name}.js</h2>
</div>
<form>
<label>
<p>Name:</p>
<input name="name" />
</label>
<div>
<button>Save</button>
</div>
</form>
</div>
)
}
在这段代码中,您useState
分解为一个变量name
来保存输入和一个被调用setName
来更新数据的函数。然后name
在预览部分显示 ,后跟.js
扩展名,就好像用户在命名文件一样。
现在您可以存储输入数据,您可以向<input>
组件添加事件处理程序。通常有几个不同的事件处理程序可以用于给定的任务。在这种情况下,您的应用程序需要捕获用户输入到元素中的数据。这种情况最常见的处理程序是onChange
,每次组件更改时都会触发。但是,你也可以使用键盘事件,如onKeyDown
,onKeyPress
和onKeyUp
。区别主要与事件何时触发以及传递给SyntheticEvent
对象的信息有关。例如,onBlur
当元素变得不聚焦时的事件在 之前触发onClick
。如果您想在另一个事件触发之前处理用户信息,您可以选择一个更早的事件。
您对事件的选择还取决于您要传递给SyntheticEvent
. onKeyPress
例如,该事件将包括charCode
用户按下的键的 ,onChange
而不包括特定的字符代码,但将包括完整的输入。如果您想根据用户按下的键执行不同的操作,这一点很重要。
对于本教程,用于onChange
捕获整个输入值,而不仅仅是最近的键。这将节省您在每次更改时存储和连接值的工作。
创建一个函数,将 theevent
作为参数并<input>
使用onChange
prop将其传递给元素:
import React, { useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
const [name, setName] = useState('');
return(
<div className="wrapper">
<div className="preview">
<h2>Preview: {name}.js</h2>
</div>
<form>
<label>
<p>Name:</p>
<input name="name" onChange={event => {}}/>
</label>
<div>
<button>Save</button>
</div>
</form>
</div>
)
}
如前所述,event
这里不是本机浏览器事件。它是SyntheticEvent
由 React 提供的,通常被视为相同。在你需要的本地事件极少数情况下,您可以使用nativeEvent
该属性SyntheticEvent
。
现在您有了事件,从target.value
事件的属性中取出当前值。将值传递给以setName
更新预览:
import React, { useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
const [name, setName] = useState('');
return(
<div className="wrapper">
<div className="preview">
<h2>Preview: {name}.js</h2>
</div>
<form>
<label>
<p>Name:</p>
<input
autoComplete="off"
name="name"
onChange={event => setName(event.target.value) }
/>
</label>
<div>
<button>Save</button>
</div>
</form>
</div>
)
}
此外,您将该属性autoComplete
设置"off"
为关闭浏览器建议。
保存文件。当您这样做时,页面将重新加载,当您输入时,<input>
您将在预览中看到更新。
注意:您还可以使用event.target.name
. 如果您在多个输入中使用相同的事件处理程序,这将非常有用,因为name
将自动匹配name
组件的属性。
此时,您有一个可用的事件处理程序。您正在获取用户信息,将其保存到状态,并使用数据更新另一个组件。但是除了从事件中提取信息之外,在某些情况下您还需要停止事件,例如,如果您想阻止表单提交或阻止按键操作。
要停止事件,请对事件调用preventDefault
操作。这将阻止浏览器执行默认行为。
在FileNamer
组件的情况下,某些字符可能会中断选择您的应用程序应该禁止的文件的过程。例如,您不希望用户向*
文件名添加 a ,因为它与通配符冲突,通配符可能被解释为引用不同的文件集。在用户提交表单之前,您需要检查以确保没有无效字符。如果存在无效字符,您将阻止浏览器提交表单并向用户显示一条消息。
首先,创建一个将生成alert
布尔值和setAlert
函数的 Hook 。然后添加一个<div>
以显示消息如果alert
为真:
import React, { useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
const [name, setName] = useState('');
const [alert, setAlert] = useState(false);
return(
<div className="wrapper">
<div className="preview">
<h2>Preview: {name}.js</h2>
</div>
<form>
<label>
<p>Name:</p>
<input
autoComplete="off"
name="name"
onChange={event => setName(event.target.value) }
/>
</label>
{alert && <div> Forbidden Character: *</div>}
<div>
<button>Save</button>
</div>
</form>
</div>
)
}
在此代码中,您使用&&
运算符仅显示新的<div>
ifalert
设置为等于true
first。<div>
will 中的消息告诉用户*
输入中不允许使用该字符。
接下来,创建一个名为validate
. 使用正则表达式 .test
方法找出字符串是否包含*
. 如果是这样,您将阻止表单提交:
import React, { useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
const [name, setName] = useState('');
const [alert, setAlert] = useState(false);
const validate = event => {
if(/\*/.test(name)) {
event.preventDefault();
setAlert(true);
return;
}
setAlert(false);
};
return(
<div className="wrapper">
<div className="preview">
<h2>Preview: {name}.js</h2>
</div>
<form>
<label>
<p>Name:</p>
<input
autoComplete="off"
name="name"
onChange={event => setName(event.target.value) }
/>
</label>
{alert && <div> Forbidden Character: *</div>}
<div>
<button onClick={validate}>Save</button>
</div>
</form>
</div>
)
}
当validate
函数被调用并且测试返回时true
,它将使用event.preventDefault
then 调用setAlert(true)
。否则,它将调用setAlert(false)
. 在代码的最后一部分中,您将事件处理程序添加到<button>
带有onClick
.
保存文件。和以前一样,您也可以使用onMouseDown
,但onClick
更常见,因此可以避免任何意外的副作用。此表单没有任何提交操作,但通过阻止默认操作,您可以阻止页面重新加载:
现在您有一个使用两个事件处理程序的表单:onChange
和onClick
。您正在使用事件处理程序将用户操作连接到组件和应用程序,使其具有交互性。在这样做的过程中,您学习了向 DOM 元素添加事件,以及如何在同一操作上触发多个事件,但它们在SyntheticEvent
. 您还学习了如何从 中提取信息SyntheticEvent
,通过将数据保存到状态来更新其他组件,以及如何使用 停止事件preventDefault
。
在下一步中,您将向单个 DOM 元素添加多个事件以处理各种用户操作。
步骤 2 — 向同一元素添加多个事件处理程序
在某些情况下,单个组件将触发多个事件,您需要能够连接到单个组件上的不同事件。例如,在此步骤中,您将使用onFocus
和onBlur
事件处理程序向用户提供有关组件的即时信息。在这一步结束时,您将更多地了解 React 中支持的不同事件以及如何将它们添加到您的组件中。
该validate
功能有助于防止您的表单提交错误数据,但对用户体验不是很有帮助:用户仅在填写整个表单后才会收到有关有效字符的信息。如果有多个字段,它不会给用户任何反馈,直到最后一步。为了使该组件对用户更加友好,通过添加onFocus
事件处理程序在用户输入字段时显示允许和不允许的字符。
首先,更新alert
<div>
以包含有关允许使用哪些字符的信息。告诉用户字母数字字符是允许的,*
不允许的:
import React, { useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
...
return(
<div className="wrapper">
<div className="preview">
<h2>Preview: {name}.js</h2>
</div>
<form>
<label>
<p>Name:</p>
<input
autocomplete="off"
name="name"
onChange={event => setName(event.target.value) }
/>
</label>
{alert &&
<div>
<span role="img" aria-label="allowed">✅</span> Alphanumeric Characters
<br />
<span role="img" aria-label="not allowed">⛔️</span> *
</div>
}
<div>
<button onClick={validate}>Save</button>
</div>
</form>
</div>
)
}
在此代码中,您使用了可访问的富 Internet 应用程序 (ARIA) 标准来使屏幕阅读器更易于访问该组件。
接下来,向<input>
元素添加另一个事件处理程序。当用户通过单击或跳入输入来激活组件时,您将提醒用户有关允许和不允许的字符。添加以下突出显示的行:
import React, { useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
...
return(
<div className="wrapper">
<div className="preview">
<h2>Preview: {name}.js</h2>
</div>
<form>
<label>
<p>Name:</p>
<input
autocomplete="off"
name="name"
onChange={event => setName(event.target.value) }
onFocus={() => setAlert(true)}
/>
</label>
{alert &&
<div>
<span role="img" aria-label="allowed">✅</span> Alphanumeric Characters
<br />
<span role="img" aria-label="not allowed">⛔️</span> *
</div>
}
<div>
<button onClick={validate}>Save</button>
</div>
</form>
</div>
)
}
您向元素添加了onFocus
事件处理程序<input>
。当用户选择字段时触发此事件。添加事件处理程序后,您传递了一个匿名函数,onFocus
该函数将调用setAlert(true)
并显示数据。在这种情况下,您不需要来自SyntheticEvent
; 的任何信息。你只需要在用户操作时触发一个事件。React 仍在向SyntheticEvent
函数发送,但在当前情况下,您不需要使用其中的信息。
注意:您可以使用onClick
或触发数据显示onMouseDown
,但对于使用键盘切换到表单字段的用户来说,这是无法访问的。在这种情况下,onFocus
事件将处理这两种情况。
保存文件。当您这样做时,浏览器将刷新并且信息将保持隐藏,直到用户单击输入。
现在用户信息会在字段聚焦时出现,但现在数据在组件的持续时间内存在。没有办法让它消失。幸运的是,onBlur
当用户留下输入时,还有另一个称为触发的事件。添加onBlur
带有匿名函数的事件处理程序,该函数会将 设置alert
为false
。就像onFocus
,这在用户点击离开或用户离开时都有效:
import React, { useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
...
return(
<div className="wrapper">
<div className="preview">
<h2>Preview: {name}.js</h2>
</div>
<form>
<label>
<p>Name:</p>
<input
autocomplete="off"
name="name"
onBlur={() => setAlert(false)}
onChange={event => setName(event.target.value) }
onFocus={() => setAlert(true)}
/>
</label>
{alert &&
<div>
<span role="img" aria-label="allowed">✅</span> Alphanumeric Characters
<br />
<span role="img" aria-label="not allowed">⛔️</span> *
</div>
}
<div>
<button onClick={validate}>Save</button>
</div>
</form>
</div>
)
}
保存文件。当你这样做时,浏览器将刷新,当用户点击元素时信息将显示,当用户点击离开时信息将消失:
您可以根据需要向元素添加任意数量的事件处理程序。如果您对需要的事件有所了解,但不确定名称,请滚动浏览支持的事件,您可能会找到所需的内容。
在此步骤中,您向单个 DOM 元素添加了多个事件处理程序。您了解了不同的事件处理程序如何处理范围广泛的事件(例如单击和选项卡)或范围狭窄的事件。
在下一步中,您将向Window
对象添加全局事件侦听器,以捕获在直接组件之外发生的事件。
第 3 步 – 添加窗口事件
在这一步中,您将用户信息放在一个弹出组件中,该组件将在用户聚焦输入时激活,并在用户单击页面上的任何其他位置时关闭。为了实现这种效果,您将使用Hook向Window
对象添加一个全局事件侦听器。您还将在组件卸载时删除事件侦听器以防止内存泄漏,当您的应用程序占用的内存超出其需要时。useEffect
在此步骤结束时,您将能够安全地添加和删除单个组件上的事件侦听器。您还将学习如何使用useEffect
Hook 在组件安装和卸载时执行操作。
在大多数情况下,您将直接向 JSX 中的 DOM 元素添加事件处理程序。这使您的代码保持专注并防止出现组件通过Window
对象控制另一个组件行为的混乱情况。但有时您需要添加全局事件侦听器。例如,您可能希望滚动侦听器加载新内容,或者您可能希望捕获组件外部的点击事件。
在本教程中,您只想向用户显示有关输入的信息(如果他们特别要求)。显示信息后,每当用户单击组件外的页面时,您都希望将其隐藏。
首先,移动alert
显示到一个新的<div>
用className
的information-wrapper
。然后添加一个带有className
of的新按钮information
和一个onClick
将调用的事件setAlert(true)
:
import React, { useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
...
return(
<div className="wrapper">
<div className="preview">
<h2>Preview: {name}.js</h2>
</div>
<form>
<label>
<p>Name:</p>
<input
autocomplete="off"
name="name"
onChange={event => setName(event.target.value) }
/>
</label>
<div className="information-wrapper">
<button
className="information"
onClick={() => setAlert(true)}
type="button"
>
more information
</button>
{alert &&
<div className="popup">
<span role="img" aria-label="allowed">✅</span> Alphanumeric Characters
<br />
<span role="img" aria-label="not allowed">⛔️</span> *
</div>
}
</div>
<div>
<button onClick={validate}>Save</button>
</div>
</form>
</div>
)
}
您还从元素中删除了onFocus
和onBlur
处理程序<input>
以删除上一步中的行为。
保存并关闭文件。然后打开FileNamer.css
:
- nano src/components/FileNamer/FileNamer.css
添加一些样式以绝对定位popup
按钮上方的信息。然后将<button>
类更改information
为蓝色,没有边框。
.information {
font-size: .75em;
color: blue;
cursor: pointer;
}
.wrapper button.information {
border: none;
}
.information-wrapper {
position: relative;
}
.popup {
position: absolute;
background: white;
border: 1px darkgray solid;
padding: 10px;
top: -70px;
left: 0;
}
.preview {
border: 1px darkgray solid;
padding: 10px;
}
.wrapper {
display: flex;
flex-direction: column;
padding: 20px;
text-align: left;
}
.wrapper button {
background: none;
border: 1px black solid;
margin-top: 10px;
}
保存并关闭文件。当您这样做时,浏览器将重新加载,当您单击 时more information
,将显示有关该组件的信息:
现在您可以触发弹出窗口,但无法清除它。要解决该问题,请添加一个全局事件侦听器,该侦听器可调用setAlert(false)
弹出窗口之外的任何单击。
事件侦听器看起来像这样:
window.addEventListener('click', () => setAlert(false))
但是,您必须注意何时在代码中设置事件侦听器。例如,您不能在组件代码的顶部添加事件侦听器,因为这样每次更改时,组件都会重新渲染并添加新的事件侦听器。由于您的组件可能会多次重新渲染,因此会创建大量占用内存的未使用的事件侦听器。
为了解决这个问题,React 有一个特殊的 Hook useEffect
,它只会在特定属性发生变化时运行。基本结构是这样的:
useEffect(() => {
// run code when anything in the array changes
}, [someProp, someOtherProp])
在简化的示例中,React 将在匿名函数中运行代码,无论何时someProp
或someOtherProp
更改。数组中的项称为依赖项。此 Hook 侦听依赖项的更改,然后在更改后运行该函数。
现在,你有工具来添加和使用安全删除全局事件侦听器useEffect
添加事件监听器,只要alert
是true
每当删除它alert
是false
。
还有一步。当组件卸载时,它将运行您从useEffect
Hook内部返回的任何函数。因此,您还需要返回一个函数,用于在组件卸载时移除事件侦听器。
基本结构是这样的:
useEffect(() => {
// run code when anything in the array changes
return () => {} // run code when the component unmounts
}, [someProp, someOtherProp])
既然您知道useEffect
Hook的形状,请在您的应用程序中使用它。打开FileNamer.js
:
- nano src/components/FileNamer/FileNamer.js
在内部, import useEffect
,然后在该函数之后的数组中添加一个具有alert
和依赖项的空匿名setAlert
函数:
import React, { useEffect, useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
const [name, setName] = useState('');
const [alert, setAlert] = useState(false);
useEffect(() => {
}, [alert, setAlert]);
...
在此代码中,您同时添加了alert
和setAlert
。为了完整起见,React 建议您将所有外部依赖项添加到useEffect
函数中。由于您将调用该setAlert
函数,因此可以将其视为依赖项。setAlert
在第一次渲染后不会改变,但包含任何可以被视为依赖的东西是一个很好的做法。
接下来,在匿名函数中,创建一个名为的新函数,该函数handleWindowClick
调用setAlert(false)
:
import React, { useEffect, useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
const [name, setName] = useState('');
const [alert, setAlert] = useState(false);
useEffect(() => {
const handleWindowClick = () => setAlert(false)
}, [alert, setAlert]);
...
}
然后添加一个条件,将调用window.addEventListener('click', handleWindowClick)
的时候alert
是true
,将调用window.removeEventListener('click', handleWindowClick)
时alert
是false
。这将在每次触发弹出窗口时添加事件侦听器,并在每次关闭弹出窗口时将其删除:
import React, { useEffect, useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
const [name, setName] = useState('');
const [alert, setAlert] = useState(false);
useEffect(() => {
const handleWindowClick = () => setAlert(false)
if(alert) {
window.addEventListener('click', handleWindowClick);
} else {
window.removeEventListener('click', handleWindowClick);
}
}, [alert, setAlert]);
...
}
最后,返回一个将删除事件侦听器的函数。再次,这将在组件卸载时运行。可能没有实时事件侦听器,但在侦听器仍然存在的情况下仍然值得清理:
import React, { useEffect, useState } from 'react';
import './FileNamer.css';
export default function FileNamer() {
const [name, setName] = useState('');
const [alert, setAlert] = useState(false);
useEffect(() => {
const handleWindowClick = () => setAlert(false)
if(alert) {
window.addEventListener('click', handleWindowClick);
} else {
window.removeEventListener('click', handleWindowClick)
}
return () => window.removeEventListener('click', handleWindowClick);
}, [alert, setAlert]);
...
}
保存文件。当您这样做时,浏览器将刷新。如果您单击更多信息按钮,则会出现该消息。如果您查看开发人员工具中的全局事件侦听器,您会看到有一个click
侦听器:
单击组件外的任意位置。该消息将消失,您将不再看到全局单击事件侦听器。
您的useEffect
Hook 基于用户交互成功添加和删除了全局事件侦听器。它不绑定到特定的 DOM 元素,而是由组件状态的更改触发。
注意:从可访问性的角度来看,该组件并不完整。如果用户无法使用鼠标,他们将被打开的弹出窗口卡住,因为他们永远无法在组件外单击。解决方案是添加另一个事件侦听器keydown
,这也将删除消息。代码几乎相同,除了方法是keydown
代替click
.
In this step you added global event listeners inside a component. You also learned how to use the useEffect
Hook to properly add and remove the event listener as the state changes and how to clean up event listeners when the component unmounts.
Conclusion
Event handlers give you the opportunity to align your components with user actions. These will give your applications a rich experience and will increase the interactive possibilities of your app. They will also give you the ability to capture and respond to user actions.
React’s event handlers let you keep your event callbacks integrated with the HTML so that you can share functionality and design across an application. In most cases, you should focus on adding event handlers directly to DOM elements, but in situations where you need to capture events outside of the component, you can add event listeners and clean them up when they are no longer in use to prevent memory leaks and create performative applications.
If you would like to look at more React tutorials, check out our React Topic page, or return to the How To Code in React.js series page. To learn more about events in JavaScript, read our Understanding Events in JavaScript and Using Event Emitters in Node.js tutorials.