NextJS中使用createPortal实现模态框报document未定义如何解决
报错原因
Next.js 默认会在服务端执行组件渲染逻辑,而服务端环境不存在浏览器专属的 document 全局对象,你直接在组件顶层执行 document.getElementById 就会触发该报错。另外你的代码还存在几处其他问题,同步修复即可。
修复步骤
- 第一步:修正你
_document.js里的节点拼写错误,确保id和你查询的名称一致:
<div id="modal-overlay"></div>
你之前步骤里写的id为modal-overaly属于拼写错误,会导致后续即便在客户端也拿不到目标节点。
- 第二步:修复Modal组件的报错,有两种常用方案可选:
方案1:使用useEffect将DOM查询逻辑移到客户端执行
无需修改父组件导入方式,直接调整Modal组件代码即可,适配TS类型后的完整代码如下:
import { createPortal } from "react-dom"; import { useEffect, useRef, useState } from "react"; // 定义组件Props的TS类型 interface ModalProps { show: boolean; } const Modal = ({ show }: ModalProps) => { // 标记是否已挂载到客户端 const [isClient, setIsClient] = useState(false); // 存储portal目标节点 const portalNodeRef = useRef<HTMLElement | null>(null); useEffect(() => { setIsClient(true); portalNodeRef.current = document.getElementById("modal-overlay"); }, []); // 未到客户端、不展示、未拿到节点时都返回null if (!isClient || !show || !portalNodeRef.current) return null; return createPortal( <div> <h1> Thank you for your inquire! We have received your message! Demelo Dining is ready to serve your upcoming event. </h1> </div>, portalNodeRef.current ); }; export default Modal;
同时要修正你之前的Props解构错误:你原有代码里写的const { showModal } = props.show是错误写法,直接传入show参数即可,父组件调用时写<Modal show={showModal} />就可以正常使用。
方案2:用Next.js的dynamic导入关闭组件服务端渲染
如果你不想修改Modal组件的逻辑,可以直接在父组件导入Modal时关闭SSR,这样Modal组件只会在客户端加载,自然不会有服务端找不到document的问题:
父组件导入代码:
import dynamic from "next/dynamic"; // 导入Modal时关闭服务端渲染 const Modal = dynamic(() => import("./Modal"), { ssr: false });
调整后的Modal组件简化代码:
import { createPortal } from "react-dom"; interface ModalProps { show: boolean; } const Modal = ({ show }: ModalProps) => { if (!show) return null; const portalElement = document.getElementById("modal-overlay"); if (!portalElement) return null; return createPortal( <div> <h1> Thank you for your inquire! We have received your message! Demelo Dining is ready to serve your upcoming event. </h1> </div>, portalElement ); }; export default Modal;
内容的提问来源于stack exchange,提问作者Felipe
相关产品推荐
相关产品推荐

