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

React Portal使用ref.current作容器报错Target container is not a DOM element

错误原因
  • React 组件的渲染流程是先执行所有子组件的渲染逻辑,再将生成的DOM节点挂载到页面,最后才给ref对象的current属性赋值。你在Page1/Page2的渲染阶段直接调用createPortal,此时父组件传递的pageTitleRef.current还未被赋值,仍然是null,所以抛出目标容器不是DOM元素的错误。
  • 额外说明:你当前代码里还存在逻辑错位问题,Page1组件内Portal渲染的是Page2 title,Page2渲染的是Page1 title,和实际页面标识不匹配,修复时可以同步调整。
解决方法

两种可行方案可按需选择:

  • 方案1:子组件内加判断,ref就绪后再渲染Portal,实现成本最低
function Page1({ pageTitleRef }) {
  return (
    <div className="Page1">
      {/* 只有ref指向真实DOM节点时才渲染Portal */}
      {pageTitleRef.current && createPortal("Page1 title", pageTitleRef.current)}
      <h2>Page 1 content!</h2>
    </div>
  );
}

function Page2({ pageTitleRef }) {
  return (
    <div className="Page2">
      {pageTitleRef.current && createPortal("Page2 title", pageTitleRef.current)}
      <h2>Page 2 content!</h2>
    </div>
  );
}
  • 方案2:父组件等待ref挂载完成后再渲染子页面,避免Portal内容延迟展示
import { useRef, useState, useEffect } from "react";
import { createPortal } from "react-dom";

export default function App() {
  const pageTitleRef = useRef(null);
  const [page, setPage] = useState(true);
  // 新增状态标记ref是否已挂载到DOM
  const [refReady, setRefReady] = useState(false);

  // 组件挂载后确认ref就绪
  useEffect(() => {
    if (pageTitleRef.current) {
      setRefReady(true);
    }
  }, [])

  return (
    <div className="App">
      <header>
        <h1>
          App-<span id="page-title" ref={pageTitleRef}></span>
        </h1>
        <button
          onClick={(e) => {
            setPage((p) => !p);
          }}
        >
          toggle page
        </button>
      </header>
      {/* ref就绪后再渲染子页面 */}
      {refReady && (page ? (
        <Page1 key="page1" pageTitleRef={pageTitleRef} />
      ) : (
        <Page2 key="page2" pageTitleRef={pageTitleRef} />
      ))}
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:24:03