You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React/Nextjs使用createPortal报错Target container is not a DOM element求助

错误原因

  • ReactDOM.createPortal 第二个参数要求传入真实存在的DOM元素对象,你当前传入的是useEffect钩子的返回值,useEffect默认返回undefined或者清理函数,永远不可能返回DOM节点,直接导致portal找不到挂载容器。
  • 你在_document.js中将id为message的容器写在了<body>标签外部,属于非法的HTML结构,浏览器解析时会自动调整节点位置,也可能导致节点获取失败。
  • Next.js 存在服务端渲染阶段,服务端运行时不存在document对象,直接调用document.getElementById会导致服务端报错,就算写法正确也会在构建/首屏渲染时报错。

修正代码

1. 修正 _document.js

把message容器移到body内部:

class MyDocument extends Document {
    render() {
        return (
            <Html>
                <Head />
                <body>
                    <Main />
                    <DeferNextScript />
                    {/* message容器移到body标签内部 */}
                    <div id="message"></div>
                </body>
            </Html>
        );
    }
}

export default MyDocument;

2. 修正 message.js

调整portal渲染逻辑,等组件客户端挂载完成后再获取DOM节点渲染:

import { useContext, useEffect, useState, useRef } from 'react'
import ReactDOM from 'react-dom'

function Message(props) {
    const messageCtx = useContext(MessageBannerContext);
    const [isClientMounted, setIsClientMounted] = useState(false)
    const messageContainerRef = useRef(null)

    // 仅在客户端挂载后获取DOM节点,避免服务端渲染报错
    useEffect(() => {
        messageContainerRef.current = document.getElementById('message')
        setIsClientMounted(true)
    }, [])

    // 未挂载完成、未拿到容器节点时不渲染portal
    if (!isClientMounted || !messageContainerRef.current) return null

    return ReactDOM.createPortal(
        <div>
            <p>Message</p>
            <button>More info</button>
            <button onClick={messageCtx.hideMessage}>Ok</button>
        </div>,
        messageContainerRef.current
    );
}

export default Message;

内容的提问来源于stack exchange,提问作者RandomDeveloper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 01:48:03