如何使用 React 处理 DOM 和窗口事件

作者选择了 Creative Commons以作为 Write for Donations计划的一部分获得捐赠。

介绍

在 Web 开发中, 事件代表了在 Web 浏览器中发生的操作. 通过使用 事件处理器响应事件,您可以创建动态的 JavaScript应用程序,以响应用户的任何操作,包括使用鼠标点击,沿网页滚动,触摸触摸屏,等等。

在 [React] (https://reactjs.org/) apps中,您可以使用事件处理器来更新状态数据,触发prop更改,或者防止默认浏览器动作. 要做到这一点,React使用合成Event包装器,而不是本地的`Event'接口。 ‘合成Event'紧密地模仿了标准的浏览器事件,但为不同的网页浏览器提供了更一致的行为. 反应还让您在组件从[文件对象模型 (DOM (https://andsky.com/tech/tutorials/introduction-to-the-dom)上起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起.

在这个教程中,你会学会如何在React中处理事件. 您将构建几个处理用户事件的样本组件,包括一个自我验证的输入组件和输入表的信息化工具提示. 在整个辅导期间,您将学习如何在组件中添加事件处理器,从合成事件中提取信息,并添加和删除Window事件听众。 到本教程结束时,你就可以与各种事件处理器合作,并应用由React所支持的事件的目录.

前提条件

  • 联合国 您需要一个运行 [Node.js] (https://nodejs.org/en/about/) 的开发环境; 此教程在 Node.js 版本 10.22.0 和 npm 版本 6.14.6. 上进行了测试 。 要在 macOS 或 Ubuntu 18.04 上安装此功能,请遵循 [如何在 macOS (https://andsky.com/tech/tutorials/how-to-install-node-js-and-create-a-local-development-environment-on-macos 上安装节点并创建本地开发环境] 或 [如何在 Ubuntu 18.04 (https://andsky.com/tech/tutorials/how-to-install-node-js-on-ubuntu-18-04 上安装节点.js] 的 ** 部分使用 PPA** 。 Create React App相接而来的一种反应开发环境,非必需锅炉板被取出. 要设置此选项, 请遵循 [* 步骤1 — 创建一个空项目** , 如何管理响应类组件的状态教程] (https://andsky.com/tech/tutorials/how-to-manage-state-on-react-class-components# step-1-%E2%80%94-creating-an-empty-project) 。 此教程将使用 活动 作为项目名称。
  • 联合国 您还需要关于 JavaScript 和 HTML 的基本知识, 您可以在 [How To Build a website with HTML series] (https://www.digitalocean.com/community/tutorial_series/how-to-build-a-website-with-html) 和 [How To Code in JavaScript] (https://www.digitalocean.com/community/tutorial_series/how-to-code-in-javascript) 中找到这些知识 。 CSS的基本知识也是有用的,你可以在Mozilla开发者网络中找到.
  • 联合国 您将使用 React 组件 " 使用状态 " 钩和 " 使用减少器 " Hook,您可以在我们的教程中学习到[如何在反应中创建自定义组件 (https://andsky.com/tech/tutorials/how-to-create-custom-components-in-react)和[如何在反应组件上用钩子管理状态 (https://andsky.com/tech/tutorials/how-to-manage-state-with-hooks-on-react-components). .

步骤 1 — 使用SyntheticEvent提取事件数据

在此步骤中,您将使用 QQinput 创建验证组件 HTML 元素和 " 变化 " 事件处理器。 此组件将接受输入并_ validate_ 它, 或确保内容符合特定的文本模式 。 您将使用 合成Event 包头将事件数据传递到 [召回函数] (https://andsky.com/tech/tutorials/how-to-write-asynchronous-code-in-node-js# asynchronous-programming-with-callbacks ) , 并使用 QQinput 的数据更新组件 。 您还将调用综合行动中的功能,如防止默认,以防止标准浏览器动作.

在 React 中,您不需要在添加事件聆听器之前选择元素。相反,您将事件处理器直接添加到您的 JSX中,使用附加功能。

与原生 DOM `onevent' 处理器不同,React 将一个名为 'SyntheticEvent' 的特殊包装传递给事件处理器,而不是原生浏览器 'Event'。

要证明这一点,您将开始通过进行验证输入。 首先,您将创建一个名为FileNamer的组件。 这将是一个<form>元素,其中有一个输入来命名一个文件。 当您填写输入时,您将看到该组件上方的信息更新预览框。

首先,创建目录:

1mkdir src/components/FileNamer

然后在文本编辑器中打开FileNamer.js:

1nano src/components/FileNamer/FileNamer.js

FileNamer.js中,创建一个包装器<div>,然后添加另一个<div>与类名称预览和包装器内的<form>元素,写下以下代码行:

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React from 'react';
 3
 4export default function FileNamer() {
 5  return(
 6    <div className="wrapper">
 7      <div className="preview">
 8      </div>
 9      <form>
10      </form>
11    </div>
12  )
13}

接下来,为预览框中显示的名称添加一个输入元素和一个 ** Save** 按钮。

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React from 'react';
 3
 4export default function FileNamer() {
 5  return(
 6    <div className="wrapper">
 7      <div className="preview">
 8        <h2>Preview:</h2>
 9      </div>
10      <form>
11        <label>
12          <p>Name:</p>
13          <input name="name" />
14        </label>
15        <div>
16          <button>Save</button>
17        </div>
18      </form>
19    </div>
20  )
21}

预览``div>中,您添加了一种<h2>元素,包含文本预览。这将是您的预览框。在您的表单中,您添加了一种<input>元素,周围有一个<label>元素,其文本是Name: 然后您在关闭<form>标签之前直接添加了一个名为Save**按钮

保存并关闭文件。

接下来,打开App.js:

1nano src/components/App/App.js

导入FileNamer,然后在App函数中渲染,添加以下突出的行:

1[label events-tutorial/src/components/App/App.js]
2import React from 'react';
3import FileNamer from '../FileNamer/FileNamer';
4
5function App() {
6    return <FileNamer />
7}
8
9export default App;

保存和关闭文件. 当你这样做时,浏览器将更新,你会看到你的组件。

Name element

接下来,添加一些轻型风格来帮助定义部分,并为元素添加一些垫和边缘。

在文本编辑器中打开FileNamer.css:

1nano src/components/FileNamer/FileNamer.css

给‘.preview’类一个灰色边界和插件,然后给‘.wrapper’类一个小量的插件。 使用‘flex’(https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox)和‘flex-direction’在列中显示项目,并将所有文本排列在左边。

 1[label events-tutorial/src/components/FileNamer/FileNamer.css]
 2.preview {
 3    border: 1px darkgray solid;
 4    padding: 10px;
 5}
 6
 7.wrapper {
 8    display: flex;
 9    flex-direction: column;
10    padding: 20px;
11    text-align: left;
12}
13
14.wrapper button {
15    background: none;
16    border: 1px black solid;
17    margin-top: 10px;
18}

保存并关闭文件,然后打开FileNamer.js:

1nano src/components/FileNamer/FileNamer.js

导入样式,将其应用于您的组件:

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6  return(
 7    <div className="wrapper">
 8      <div className="preview">
 9        <h2>Preview:</h2>
10      </div>
11      <form>
12        <label>
13          <p>Name:</p>
14          <input name="name" />
15        </label>
16        <div>
17          <button>Save</button>
18        </div>
19      </form>
20    </div>
21  )
22}

当你这样做时,浏览器将更新,你会发现该组件有新的风格。

Styled component

现在你有一个基本组件,你可以添加事件处理器到<input>元素,但首先,你需要一个地方来存储数据在输入字段。

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6  const [name, setName] = useState('');
 7  return(
 8    <div className="wrapper">
 9      <div className="preview">
10        <h2>Preview: {name}.js</h2>
11      </div>
12      <form>
13        <label>
14          <p>Name:</p>
15          <input name="name" />
16        </label>
17        <div>
18          <button>Save</button>
19        </div>
20      </form>
21    </div>
22  )
23}

在此代码中,您将useState摧毁为一个变量name以保留输入和一个名为setName的函数来更新数据,然后您在预览部分中显示了name.js扩展,就像用户正在命名文件一样。

现在可以存储输入数据,可以在QQinput>组件中添加一个事件处理器. 经常有几种不同的事件处理器可以用于特定的任务. 在这种情况下,您的应用程序需要将用户类型的数据捕获到元素中. 这种情况最常见的处理者是 " 变化 " ,这种变化在组件变化时都会起火。 然而,你也可以使用键盘事件(https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent),如上键盘上键盘上键盘。 区别主要在于事件何时起火和传递给合成事件 ' 对象的信息。 例如,on Blur',当某一元素变得不突出重点时,在onClick'前起火。 如果您想在另一事件起火前处理用户信息,可以选择更早的事件.

例如,onKeyPress事件将包含用户按下的密钥的charCode,而onChange不会包含特定字符代码,但将包含完整的输入。

对于本教程,使用onChange来捕捉整个输入值,而不仅仅是最新的密钥。

创建一个将事件作为参数的函数,并使用onChange口号将其传送到<input>元素:

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6  const [name, setName] = useState('');
 7  return(
 8    <div className="wrapper">
 9      <div className="preview">
10        <h2>Preview: {name}.js</h2>
11      </div>
12      <form>
13        <label>
14          <p>Name:</p>
15          <input name="name" onChange={event => {}}/>
16        </label>
17        <div>
18          <button>Save</button>
19        </div>
20      </form>
21    </div>
22  )
23}

如前所述,这里的事件不是本源浏览器的事件,而是 React 提供的SyntheticEvent,通常被视为相同的事件,在罕见的情况下,您需要本源事件,您可以在SyntheticEvent上使用nativeEvent属性。

现在你有事件,从事件的target.value属性中提取当前值,将该值传输到setName,以更新预览:

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6  const [name, setName] = useState('');
 7  return(
 8    <div className="wrapper">
 9      <div className="preview">
10        <h2>Preview: {name}.js</h2>
11      </div>
12      <form>
13        <label>
14          <p>Name:</p>
15          <input
16           autoComplete="off"
17           name="name"
18           onChange={event => setName(event.target.value) }
19         />
20        </label>
21        <div>
22          <button>Save</button>
23        </div>
24      </form>
25    </div>
26  )
27}

此外,您还将属性 autoComplete设置为关闭以关闭浏览器建议。

当您这样做时,页面将重新加载,当您键入<input>时,您将在预览中看到更新。

Typing into the input element

注意:** 您还可以使用 event.target.name 访问输入名称,如果在多个输入中使用相同的事件处理器,这将是有用的,因为 name 会自动匹配组件的 name 属性。

在此时,您有一个工作事件处理器. 您正在使用用户信息,将其保存为声明,并与数据更新其他组件. 但是,除了从事件中提取信息外,还有一些情况需要停止事件,例如,如果您想要阻止表单提交或防止键盘操作。

要停止一个事件,请在该事件上调用preventDefault操作,这将阻止浏览器执行默认行为。

对于 FileNamer 组件, 某些字符可能会打破选择应用程序应禁止的文件的进程 。 例如,您不会希望用户在文件名中添加一个QQ,因为它与通配符字符相冲突,而通配符可以被解释为指不同的一组文件. 在用户提交表单之前,您会想要检查以确保没有无效字符. 如果存在无效字符,则会阻止浏览器提交表单,并为用户显示消息.

首先,创建一个链接,将生成一个警告 boolean和一个设置警告函数,然后添加一个<div>来显示消息如果警告是真的:

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6  const [name, setName] = useState('');
 7  const [alert, setAlert] = useState(false);
 8
 9  return(
10    <div className="wrapper">
11      <div className="preview">
12        <h2>Preview: {name}.js</h2>
13      </div>
14      <form>
15        <label>
16          <p>Name:</p>
17          <input
18            autoComplete="off"
19            name="name"
20            onChange={event => setName(event.target.value) }
21          />
22        </label>
23        {alert && <div> Forbidden Character: *</div>}
24        <div>
25          <button>Save</button>
26        </div>
27      </form>
28    </div>
29  )
30}

在此代码中,您只使用&&运算符显示新的<div>,如果警告先设置为

接下来,创建一个名为验证的函数. 使用 正常表达式 [.test' 方法](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test)来确定字符串是否包含一个 *`。

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6  const [name, setName] = useState('');
 7  const [alert, setAlert] = useState(false);
 8  const validate = event => {
 9    if(/\*/.test(name)) {
10      event.preventDefault();
11      setAlert(true);
12      return;
13    }
14      setAlert(false);
15 };
16
17  return(
18    <div className="wrapper">
19      <div className="preview">
20        <h2>Preview: {name}.js</h2>
21      </div>
22      <form>
23        <label>
24          <p>Name:</p>
25          <input
26            autoComplete="off"
27            name="name"
28            onChange={event => setName(event.target.value) }
29          />
30        </label>
31        {alert && <div> Forbidden Character: *</div>}
32        <div>
33          <button onClick={validate}>Save</button>
34        </div>
35      </form>
36    </div>
37  )
38}

验证函数被调用,并且测试返回,它将使用event.preventDefault,然后调用setAlert(true)

保存文件. 和以前一样,你也可以使用onMouseDown,但onClick更常见,因此可以避免任何意想不到的副作用. 此表单没有任何提交操作,但通过阻止默认操作,您可以防止页面重新加载:

Prevent Default and trigger a warning

现在的表格使用两个事件处理器: " 改变 " 和 " 点击 " 。 您正在使用事件处理器将用户动作连接到组件和应用程序,使其具有交互性 。 在这样做时,你学会了将事件添加到DOM元素中,以及如何发生数起事件对同一种动作起火,但在"合成事件"中提供不同信息. 您还学会了如何从合成行动中提取信息,通过将数据保存到状态来更新其他组件,并使用预防缺陷停止事件.

在下一步中,您将向单个 DOM 元素添加多个事件,以处理各种用户操作。

步骤 2 — 将多个事件处理器添加到同一个元素中

有些情况下,单个组件会发射多个事件,您需要能够连接到单个组件上的不同事件,例如,在这个步骤中,您将使用onFocusonBlur事件处理器为用户提供有关该组件的及时信息。

验证函数有助于防止您的表单提交不良数据,但对于用户体验来说并不太有用:用户在填写整个表单后才会收到有关有效字符的信息。

首先,更新警告``<div>,以包含有关允许哪些字符的信息。

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6...
 7  return(
 8    <div className="wrapper">
 9      <div className="preview">
10        <h2>Preview: {name}.js</h2>
11      </div>
12      <form>
13        <label>
14          <p>Name:</p>
15          <input
16            autocomplete="off"
17            name="name"
18            onChange={event => setName(event.target.value) }
19          />
20        </label>
21        {alert &&
22         <div>
23           <span role="img" aria-label="allowed"></span> Alphanumeric Characters
24           <br />
25           <span role="img" aria-label="not allowed">⛔️</span> *
26         </div>
27       }
28        <div>
29          <button onClick={validate}>Save</button>
30        </div>
31      </form>
32    </div>
33  )
34}

在此代码中,您使用了 Accessible Rich Internet Applications (ARIA) 标准来使该组件更容易访问屏幕读者。

接下来,将另一个事件处理器添加到<input>元素中. 您将通过点击或键入输入来提醒用户在激活组件时允许和禁止的字符。

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6...
 7  return(
 8    <div className="wrapper">
 9      <div className="preview">
10        <h2>Preview: {name}.js</h2>
11      </div>
12      <form>
13        <label>
14          <p>Name:</p>
15          <input
16            autocomplete="off"
17            name="name"
18            onChange={event => setName(event.target.value) }
19            onFocus={() => setAlert(true)}
20          />
21        </label>
22        {alert &&
23          <div>
24            <span role="img" aria-label="allowed"></span> Alphanumeric Characters
25            <br />
26            <span role="img" aria-label="not allowed">⛔️</span> *
27          </div>
28        }
29        <div>
30          <button onClick={validate}>Save</button>
31        </div>
32      </form>
33    </div>
34  )
35}

输入元素中添加了焦点事件处理器。 此事件在用户选择字段时触发 。 在添加事件处理器后,您将一个匿名功能传递给焦点,该功能将调用setAlert(真实)并显示数据。 在这种情况下,你不需要合成活动的任何信息;只需要在用户行事时触发事件即可。 反应仍然在向该功能发送"合成Event",但在目前的情况下,你不需要使用其中的信息.

<$>[注] ** 注意:** 您可以使用onClick或甚至onMouseDown触发数据显示,但那些使用键盘键入表单字段的用户无法访问它。

当您这样做时,浏览器将更新,信息将保持隐藏,直到用户点击输入。

Trigger the event when clicking on the input

用户信息现在出现在焦点字段时,但现在数据存在于组件的持续时间。没有办法让它消失. 幸运的是,有另一个名为onBlur的事件,当用户离开一个输入时会点燃。 添加一个匿名函数的onBlur事件处理器,将警报设置为

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6...
 7  return(
 8    <div className="wrapper">
 9      <div className="preview">
10        <h2>Preview: {name}.js</h2>
11      </div>
12      <form>
13        <label>
14          <p>Name:</p>
15          <input
16            autocomplete="off"
17            name="name"
18            onBlur={() => setAlert(false)}
19            onChange={event => setName(event.target.value) }
20            onFocus={() => setAlert(true)}
21          />
22        </label>
23        {alert &&
24          <div>
25            <span role="img" aria-label="allowed"></span> Alphanumeric Characters
26            <br />
27            <span role="img" aria-label="not allowed">⛔️</span> *
28          </div>
29        }
30        <div>
31          <button onClick={validate}>Save</button>
32        </div>
33      </form>
34    </div>
35  )
36}

当您这样做时,浏览器将更新,用户点击该元素时将显示信息,当用户点击时将消失:

Show information on focus and hide on blur

如果您对所需的事件有想法,但不确定该事件的名称,请浏览支持的事件(https://reactjs.org/docs/events.html# supported-events),然后您可以找到所需的内容。

在此步骤中,您将多个事件处理器添加到单个 DOM 元素中,您了解了不同事件处理器如何处理广泛的事件(如单击和标签)或狭窄的事件范围。

在下一步中,您将向窗口对象添加全球事件倾听者,以捕捉即时组件之外发生的事件。

第3步:添加窗口事件

在此步骤中,您将将用户信息放置在一个 pop-up 组件中,该组件将在用户聚焦输入时启用,并在用户点击页面上的其他位置时关闭。

到此步骤结束时,您将能够安全地在单个组件上添加和删除事件收听器,您还将学习如何使用useEffect链接执行组件加载和卸载时的操作。

在大多数情况下,您将直接将事件处理器添加到 JSX 中的 DOM 元素中。这将使您的代码保持聚焦,并防止在某个组件通过窗口对象控制另一个组件的行为时出现混乱的情况。

在本教程中,您只希望向用户显示有关输入的信息,如果他们具体要求它,然后在显示信息后,您将希望在用户单击组件外面的页面时隐藏它。

首先,将警告显示屏移动到一个新的<div>显示器中,包含信息包装器类名称

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6...
 7  return(
 8    <div className="wrapper">
 9      <div className="preview">
10        <h2>Preview: {name}.js</h2>
11      </div>
12      <form>
13        <label>
14          <p>Name:</p>
15          <input
16            autocomplete="off"
17            name="name"
18            onChange={event => setName(event.target.value) }
19          />
20        </label>
21        <div className="information-wrapper">
22          <button
23            className="information"
24            onClick={() => setAlert(true)}
25            type="button"
26          >
27            more information
28          </button>
29         {alert &&
30           <div className="popup">
31             <span role="img" aria-label="allowed"></span> Alphanumeric Characters
32             <br />
33             <span role="img" aria-label="not allowed">⛔️</span> *
34           </div>
35         }
36        </div>
37        <div>
38          <button onClick={validate}>Save</button>
39        </div>
40      </form>
41    </div>
42  )
43}

您还从<input>元素中删除了onFocusonBlur处理器,以从最后一步中删除行为。

保存并关闭文件,然后打开FileNamer.css:

1nano src/components/FileNamer/FileNamer.css

添加一些风格,绝对地将弹出式信息放置在按钮上方,然后用信息一类的<按钮>更改为无边界的蓝色。

 1[label events-tutorial/src/components/FileNamer/FileNamer.css]
 2
 3.information {
 4   font-size: .75em;
 5   color: blue;
 6   cursor: pointer;
 7}
 8
 9.wrapper button.information {
10    border: none;
11}
12
13.information-wrapper {
14   position: relative;
15}
16
17.popup {
18    position: absolute;
19    background: white;
20    border: 1px darkgray solid;
21    padding: 10px;
22    top: -70px;
23    left: 0;
24}
25
26.preview {
27    border: 1px darkgray solid;
28    padding: 10px;
29}
30
31.wrapper {
32    display: flex;
33    flex-direction: column;
34    padding: 20px;
35    text-align: left;
36}
37
38.wrapper button {
39    background: none;
40    border: 1px black solid;
41    margin-top: 10px;
42}

当您这样做时,浏览器将重新加载,当您点击更多信息时,将显示有关组件的信息:

Trigger information pop-up

现在你可以触发弹出窗口,但没有办法清除它. 要解决这个问题,添加一个全球事件倾听器,在弹出窗口以外的任何点击时呼叫setAlert(false)

活动听众会看起来像这样的东西:

1window.addEventListener('click', () => setAlert(false))

例如,您不能在组件代码的顶部添加事件倾听器,因为每次发生变化时,组件会重新渲染并添加新的事件倾听器。

为了解决这一问题,React 拥有一个名为useEffect的特殊钩子,只有当特定的属性改变时才会运行。

1useEffect(() => {
2 // run code when anything in the array changes
3}, [someProp, someOtherProp])

在简化示例中,React 会在somePropsomeOtherProp的变化时在匿名函数中运行代码。

现在,您可以使用useEffect安全地添加和删除全球事件收听器,在警告时添加事件收听器,并在警告时删除它。

当组件卸载时,它将运行您从useEffect链接中返回的任何函数. 由于此,您还需要返回一个函数,该函数卸载时将删除事件倾听器。

基本结构将是这样的:

1useEffect(() => {
2 // run code when anything in the array changes
3  return () => {} // run code when the component unmounts
4}, [someProp, someOtherProp])

现在你已经知道你的useEffect链接的形状了,在你的应用程序中使用它。

1nano src/components/FileNamer/FileNamer.js

在里面,导入useEffect,然后在函数之后的阵列中添加一个空的匿名函数,其中有alertsetAlert的依赖性:

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useEffect, useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6  const [name, setName] = useState('');
 7  const [alert, setAlert] = useState(false);
 8
 9  useEffect(() => {
10  }, [alert, setAlert]);
11...

在此代码中,您添加了警告设置警告。 要完成,React 建议您将所有外部依赖性添加到使用效应函数中。

接下来,在匿名函数中,创建一个名为handleWindowClick的新函数,该函数呼叫setAlert(false):

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useEffect, useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6  const [name, setName] = useState('');
 7  const [alert, setAlert] = useState(false);
 8
 9  useEffect(() => {
10    const handleWindowClick = () => setAlert(false)
11  }, [alert, setAlert]);
12  ...
13}

然後添加一個 條件,當「alert」為「true」時,將呼叫「window.addEventListener('click', handleWindowClick')」並在「alert」為「false」時呼叫「window.removeEventListener ('click', handleWindowClick')。

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2import React, { useEffect, useState } from 'react';
 3import './FileNamer.css';
 4
 5export default function FileNamer() {
 6  const [name, setName] = useState('');
 7  const [alert, setAlert] = useState(false);
 8
 9  useEffect(() => {
10    const handleWindowClick = () => setAlert(false)
11    if(alert) {
12      window.addEventListener('click', handleWindowClick);
13    } else {
14      window.removeEventListener('click', handleWindowClick);
15    }
16  }, [alert, setAlert]);
17  ...
18}

最后,返回一个将删除事件倾听器的函数. 再一次,当组件卸载时,此功能将运行. 可能没有现场事件倾听器,但在听器仍然存在的情况下仍然值得清理:

 1[label events-tutorial/src/components/FileNamer/FileNamer.js]
 2
 3import React, { useEffect, useState } from 'react';
 4import './FileNamer.css';
 5
 6export default function FileNamer() {
 7  const [name, setName] = useState('');
 8  const [alert, setAlert] = useState(false);
 9
10  useEffect(() => {
11    const handleWindowClick = () => setAlert(false)
12    if(alert) {
13      window.addEventListener('click', handleWindowClick);
14    } else {
15      window.removeEventListener('click', handleWindowClick)
16    }
17    return () => window.removeEventListener('click', handleWindowClick);
18  }, [alert, setAlert]);
19  ...
20}

保存文件. 当您这样做时,浏览器将更新. 如果您点击 ** 更多信息** 按钮,消息将出现. 如果您查看开发人员工具中的全球事件倾听器,您将看到一个点击倾听器:

Click event listener

点击组件以外的任何位置. 消息将消失,您将不再看到全球点击事件倾听器。

No click event listener

您的useEffect胡克成功地添加并删除了基于用户交互的全球事件倾听器,而不是与特定DOM元素相关联,而是由组件状态的变化引发。

<$>[注] 注: 从可用性角度来看,这个组件不是完整的。如果用户无法使用鼠标,他们将被困在一个打开的弹出窗口,因为他们永远无法在组件之外点击。

在此步骤中,您已在组件内添加了全球事件倾听器,您还了解如何使用useEffect链接以正确地添加和删除事件倾听器,因为状态发生变化,以及如何清理组件卸载时的事件倾听器。

结论

事件处理器为您提供了将您的组件与用户操作相匹配的机会,这些将为您的应用程序提供丰富的体验,并增加您的应用程序的互动可能性,还将为您提供捕捉和响应用户操作的能力。

在大多数情况下,您应该专注于将事件处理器直接添加到 DOM 元素中,但在需要捕捉组件外部事件的情况下,您可以添加事件收听器并在不再使用时清理它们,以防止记忆泄漏并创建性能应用程序。

如果您想查看更多 React 教程,请查看我们的 React 主题页面,或返回 如何在 React.js 系列中编码页面. 有关 JavaScript 中的事件的更多信息,请阅读我们的 理解 JavaScript 中的事件使用 Node.js 中的事件发射器教程。

Published At
Categories with 技术
comments powered by Disqus