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
相关产品推荐
相关产品推荐

