ReactDOM.createPortal() 在 next.js-typescript 中创建额外的空白 div

问题描述

这是background.tsx:

interface BacdropProps {
  open?: string;
  onClick: () => void;
}

const Backdrop: React.FC<BacdropProps> = (props) => {
  let container: HTMLdivelement | null = null;
  if (typeof window !== "undefined") {
    const rootContainer = document.createElement("div");
    const parentElem = document.querySelector("#__next");
    parentElem?.insertAdjacentElement("afterend",rootContainer);
    // parentElem?.after(rootContainer) this gives me same issue
    container = rootContainer;
  }

  return container
    ? ReactDOM.createPortal(
        <div
          className={["backdrop",props.open ? "open" : ""].join(" ")}
          onClick={props.onClick}
        />,container
      )
    : null;
};

export default Backdrop;

这是 Backdoor.tsx 的 css

.backdrop {
  width: 100%;
  height: 100vh;
  background: rgba(0,0.75);
  z-index: 100;
  position: fixed;
  left: 0;
  top: 0;
  transition: opacity 0.3s ease-out;
  opacity: 1;
}

这是它的样子:

enter image description here

解决方法

您的代码将在每次 div.backdrop 重新渲染时创建 Backdrop。正确的方法应该是创建一次。正确的方法是使用 useEffect 来保证 ReactDOM.createPortal 只执行一次。并应用 useRef 以确保 container 在每次渲染中保持相同的实例。

const containerRef = useRef<HTMLDivElement>(null);

useEffect({
  // Will be execute once in client-side
  if (typeof window !== "undefined") {
    const rootContainer = document.createElement("div");
    const parentElem = document.querySelector("#__next");
    parentElem?.insertAdjacentElement("afterend",rootContainer);
    // parentElem?.after(rootContainer) this gives me same issue
    containerRef.current = rootContainer;
  }
},[window])

useEffect({
  // Will be execute once when containerRef is bind to <HTMLDivElement>
  if(containerRef.current) {
    ReactDOM.createPortal(
      <div
        className={["backdrop",props.open ? "open" : ""].join(" ")}
        onClick={props.onClick}
      />,containerRef.current
    )
  }
},[containerRef])

编辑

  1. 我删除了 window 中的存在检测,因为 useEffect 只会在客户端执行。

  2. 由于 ReactDOM.createPortal 将在根 div.backdrop (HTMLElement) 之外创建 div#next,我认为只需在 {{1} 中返回 null }} 组件很好。

Backdrop

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...