弹出窗口的React门户创建了不匹配的实例

问题描述 投票:1回答:1

更新

似乎每个新窗口/ iframe / etc都有自己的一组类,因此instanceof不会工作,因为它们实际上并不是同一个实例。虽然不确定解决方案,但库不使用instanceof进行检查。

TLDR:instanceof在看似相同的实例/代码上表现不同。

我正在构建一个React后台界面,它包含一个地图(mapbox),并希望添加一个功能来弹出地图,以便用户可以在单独的显示器上查看它。

使用React.createPortal,您可以将组件渲染到一个可以很好地工作的window.open元素。除了mapbox。问题不是直接与mapbox有关,mapbox将其映射到容器中,在实例化地图时将此容器作为参数提供。 Mapbox检查此容器是否为字符串,或者:

instanceof HTMLElement

这在正常渲染Component时有效,但在将组件渲染到弹出/门户时失败,突然容器检查失败。

我已经能够在codeandbox中重现这个:https://codesandbox.io/s/qllpz89w39

问题 - 有没有人知道导致这种行为的原因是什么? - 有没有办法将容器“转换”为HTMLElement

源代码:

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>
  );
}
javascript reactjs
1个回答
0
投票

非常有趣,因为你自己说一个新窗口有自己的一组类,它们的引用不匹配。即:

window.HTMLElement !== popupWindow.HTMLElement

在您的codesandbox示例中,您可以按如下方式更改检查,您将看到它将在弹出窗口中开始实现并在主窗口中失败:

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

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

popupWindow.HTMLElement = HTMLElement

但它不起作用,所以我认为选项是:

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

但我认为正确的选项是选项#1,因为如果你打算实现这样的跨窗口JS代码,我真的不确定是否会有其他陷阱。

© www.soinside.com 2019 - 2024. All rights reserved.