为什么react-select的菜单选择的setState使模态关闭状态?

Sub*_*ndu 4 javascript reactjs react-select

我有一个模态,它监听模态的外部点击并触发关闭模态的 onclose 方法。现在,我将反应选择添加到模式中,选择其中一个选项后,它使我的模式进入关闭状态。我正在从一篇媒体文章中捕获外部点击。

function useOuterClickNotifier(onOuterClick, innerRef) {
  useEffect(() => {
    if (innerRef.current) {
      document.addEventListener("click", handleClick);
    }
    return () => document.removeEventListener("click", handleClick);

    function handleClick(e) {
      if (innerRef.current && !innerRef.current.contains(e.target)) {
        onOuterClick(e);
      }
    }
  }, [onOuterClick, innerRef]);
}

Run Code Online (Sandbox Code Playgroud)

https://medium.com/@pitipatdop/little-neat-trick-to-capture-click-outside-with-react-hook-ba77c37c7e82

我的index.js

import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import Select from "react-select";
import Modal from "../Modal";

const options = [
  { value: "chocolate", label: "Chocolate" },
  { value: "strawberry", label: "Strawberry" },
  { value: "vanilla", label: "Vanilla" }
];

function App() {
  const [isOpen, setOpen] = useState(false);
  function onCloseModal() {
    console.log("Why closing?");
    setOpen(false);
  }

  function openModal() {
    setOpen(true);
  }
  return (
    <>
      {isOpen && (
        <Modal closeModal={onCloseModal}>
          <div className="card">
            <Select options={options} />
          </div>
        </Modal>
      )}
      <button onClick={openModal}>Open modal</button>
    </>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Run Code Online (Sandbox Code Playgroud)

我如何解决它?

https://codesandbox.io/s/usegooglemap-repro-x3q37?fontsize=14&hidenavigation=1&theme=dark

系统信息

System:
    OS: macOS 10.14.5
    CPU: (12) x64 Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz
  Binaries:
    Node: 12.4.0 - ~/.nvm/versions/node/v12.4.0/bin/node
    Yarn: 1.16.0 - ~/.nvm/versions/node/v12.4.0/bin/yarn
    npm: 6.9.0 - ~/.nvm/versions/node/v12.4.0/bin/npm
  Browsers:
    Chrome: 78.0.3904.97
    Firefox: 69.0
    Safari: 12.1.1
  npmPackages:
    react: 16.11.0 => 16.11.0 
    react-dom: 16.11.0 => 16.11.0 
    react-scripts: 3.2.0 => 3.2.0 
Run Code Online (Sandbox Code Playgroud)

tri*_*ixn 5

我相信这是由于调用钩子的事件侦听器时选择菜单已经被卸载所致。React 不知道手动附加的点击处理程序,因此它将立即开始更新 DOM。当您的侦听器处理该事件时,单击的 DOM 节点已被删除。

为了防止这种情况,您可以将true第三个参数传递给addEventListenerand removeEventListener。这个参数是useCapture。如果true它会在捕获阶段在目标元素的任何侦听器之前调用您的侦听器。

来自MDN

useCapture [选修的]

一个布尔值,指示此类型的事件在分派到 DOM 树中其下方的listener任何事件之前是否将分派到已注册的事件。EventTarget通过树向上冒泡的事件不会触发指定使用捕获的侦听器。事件冒泡和捕获是传播嵌套在另一个元素中的元素中发生的事件的两种方法,当两个元素都注册了该事件的句柄时。事件传播模式决定了元素接收事件的顺序。有关详细说明,请参阅 DOM Level 3 事件和 JavaScript 事件顺序。如果未指定,useCapture则默认为false.

编辑 useGoogleMap 重现

function useOuterClickNotifier(onOuterClick, innerRef) {
  useEffect(() => {
    if (innerRef.current) {
      document.addEventListener("click", handleClick, true);
    }
    return () => document.removeEventListener("click", handleClick, true);

    function handleClick(e) {
      if (innerRef.current && !innerRef.current.contains(e.target)) {
        onOuterClick(e);
      }
    }
  }, [onOuterClick, innerRef]);
}
Run Code Online (Sandbox Code Playgroud)