对弹出窗口的反应门户创建了不匹配的实例



update

似乎每个新窗口/iframe/etc都有自己的一组类,因此实例无法使用,因为它们实际上不是同一实例。不过,还不确定该解决方案,除了库不使用Instance OF检查。

tldr :实例在看似相同的实例/代码上行为不同。

我正在构建一个合并地图(MAPBOX)的React后台接口,并想添加一个功能以弹出地图,以便用户可以在单独的显示器上查看它。

使用React.CreatePortal,您可以将组件渲染到窗口。开放元素可正常工作。除了mapbox。不过,此问题不是直接与MAPBOX有关的,MapBox将其映射到一个容器中,您可以在实例化地图时提供该容器作为参数。MAPBOX检查此容器是否是字符串,还是:

instanceof HTMLElement

在正常呈现组件时起作用,但在将组件渲染到弹出/门户时会失败,突然 containe 检查失败。

我已经能够在代码框中复制此内容:https://codesandbox.io/s/qllpz89w39

问题 - 有人知道是什么原因导致这种行为? - 有没有办法将容器"铸造"到htmlelemt

源代码:

import React from "react";
import ReactDOM from "react-dom";
function App() {
  return (
    <div className="App">
      <h1>Weird bug</h1>
      <PortalTest t="Normal" />
      <WithPortal>
        <PortalTest t="In Portal" />
      </WithPortal>
    </div>
  );
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
function WithPortal({ children }) {
  const div = document.createElement("div");
  const popupWindow = window.open(
    "",
    "test",
    "width=600px,height=640px,left=100,top=100,toolbar=no,menubar=no,location=no"
  );
  if (!popupWindow) {
    return (
      <div style={{ background: "red", padding: "16px", color: "white" }}>
        <h1>Popup blocked</h1>
        <p>Please allow popups for codesandbox to see the full script</p>
      </div>
    );
  }
  popupWindow.document.body.appendChild(div);
  return ReactDOM.createPortal(children, div);
}
function PortalTest({ t }) {
  const ref = React.useRef(null);
  const [value, setValue] = React.useState("idle");
  const [el, setEl] = React.useState(null);
  React.useEffect(
    () => {
      if (el) {
        if (el instanceof HTMLElement) {
          setValue("HTMLElement");
        } else {
          setValue("Unknown");
        }
      }
    },
    [el]
  );
  function setRef(x) {
    setEl(x);
  }
  return (
    <div ref={setRef}>
      <h3>{t}</h3>
      Found ref type: {value}
    </div>
  );
}

非常有趣,因此,正如您所说的那样,一个新窗口具有自己的一组类,其参考文献不匹配。即:

window.HTMLElement !== popupWindow.HTMLElement

在您的codesandbox示例中,您可以按以下方式更改检查检查,并且您会看到条件将在弹出窗口中开始满足并在主窗口中失败:

if (el instanceof popupWindow.HTMLElement) {
  setValue("HTMLElement");
} else {
  setValue("Unknown");
}

我的第一个目的是尝试重新分配popupWindow.HTMLElement

popupWindow.HTMLElement = HTMLElement

但是它没有用,所以我认为选项是:

  1. 实现一个单独的URL,该URL将返回带有MAPBOX的React应用程序,并通过window.open()
  2. 打开其URL
  3. 调整库instanceof HTMLElement检查以考虑一个窗口上下文(您应该以某种方式通过)

,但我相信正确的选项是选项#1,因为我真的不确定如果您要实施此类跨窗口JS代码,我真的不确定会有其他陷阱。

最新更新