问题描述
这是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;
}
解决方法
您的代码将在每次 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])
编辑
-
我删除了
window
中的存在检测,因为useEffect
只会在客户端执行。 -
由于
ReactDOM.createPortal
将在根div.backdrop
(HTMLElement
) 之外创建div#next
,我认为只需在 {{1} 中返回null
}} 组件很好。
Backdrop