我有两个组件,父组件(App)显示了一个按钮,该按钮在被单击时有条件地呈现Child组件.

Here是Sandbox .

App.js

import { useState } from "react";
import Child from "./Child";

function App() {
  const [value, setValue] = useState(false);

  return (
    <div>
      <button onClick={() => setValue(true)}>Mount Child</button>
      {value ? <Child /> : null}
    </div>
  );
}

export default App;

Child.js

import React, { useEffect } from "react";

function Child() {
  const handleClick = () => {
    console.log("hi");
  };

  useEffect(() => {
    document.addEventListener("click", handleClick);

    return () => {
      document.removeEventListener("click", handleClick);
      console.log("unmounting");
    };
  });

  return <div>Child</div>;
}

export default Child;

为什么这里添加的document.addEventListener("click", handleClick)事件在登上Child时会被解雇?

这是点击按钮后的控制台:

unmounting 
hi 

React.StrictMode组件中运行unmounting是可以理解的,但我不知道为什么"hi"会被记录下来.

推荐答案

这是一个奇怪的行为,但似乎"mount Child"按钮Click被传播到了documentChild组件的useEffect钩子的回调中,添加了"Click"事件的侦听器仍然能够拾取该Click事件并触发handleClick回调.

我建议阻止按钮的点击事件传播...用户正在单击按钮,而不仅仅是文档中的任何位置,对吧.

示例:

import { useState } from "react";
import Child from "./Child";

function App() {
  const [value, setValue] = useState(false);

  const clickHandler = e => {
    e.stopPropagation(); // <-- prevent click event propagation up the DOM
    setValue(true);
  }

  return (
    <div>
      <button onClick={clickHandler}>Mount Child</button>
      {value && <Child />}
    </div>
  );
}

export default App;

此外,在Child组件中有一些关于useEffect挂钩和事件侦听器逻辑的逻辑错误.useEffect钩子缺少依赖项数组,因此无论何时呈现Child,它都会删除并重新添加Click事件侦听器.handleClick也被声明107useEffect钩子,因此它是一个外部依赖项,在每个呈现周期中被重新声明,并且还将在每次呈现时触发useEffect钩子.应该移到效果回调中.

在这里,我们添加一个空的依赖项数组,以便每次组件挂载时效果只运行一次,建立事件侦听器,并在组件卸载时删除它们.

示例:

import React, { useEffect } from "react";

function Child() {
  useEffect(() => {
    const handleClick = () => {
      console.log("hi");
    };

    document.addEventListener("click", handleClick);

    return () => {
      document.removeEventListener("click", handleClick);
      console.log("unmounting");
    };
  }, []);

  return <div>Child</div>;
}

export default Child;

Edit click-event-added-by-addeventlistener-in-useeffect-get-fired-on-mounting-the-com

Javascript相关问答推荐

无法在page. evalve()内部使用外部函数

如何比较嵌套对象的更改并创建更改报告

如何在dataTables PDF输出中正确渲染字形?

基于每个索引迭代嵌套对象

Angular:ng-contract未显示

React对话框模式在用户单击预期按钮之前出现

如何保持子画布元素的1:1宽高比?

布局样式在刷新时不持续

从连接字符串创建客户端时,NodeJS连接到CosmosDB失败

每次子路由重定向都会调用父加载器函数

从实时数据库(Firebase)上的子类别读取数据

单击子元素时关闭父元素(JS)

我可以使用使用node.js创建的本地主机来存储我网站上提交的所有数据吗?没有SQL或任何数据库.只有HTML语言

如何在FastAPI中为通过file:/URL加载的本地HTML文件启用CORS?

在JS中动态创建对象,并将其追加到HTML表中

如何确保预订系统跨不同时区的日期时间处理一致?

如何在Java脚本中对列表中的特定元素进行排序?

图表4-堆叠线和条形图之间的填充区域

如何在Highlihte.js代码区旁边添加行号?

如何在Web项目中同步语音合成和文本 colored颜色 更改