React Portals报错‘Target container is not a DOM element’排查求助
React Portal报错「Target container is not a DOM element」原因及解决
错误原因
- DOM元素未挂载就执行查找:你在
ButtonsPortal组件初始化时直接调用document.getElementById('table-buttons'),此时Table组件里的目标div还没被React渲染到真实DOM中,返回结果为null,导致createPortal因接收无效容器报错。 - 条件渲染导致容器可能不存在:目标div仅在
actionRender为true时才会渲染,若actionRender为false,该div根本不会出现在DOM中,同样会触发查找失败。
解决方法
放弃全局ID查找的方式,改用React的useRef获取目标容器的引用,并确保只有当容器存在时才渲染Portal,具体修改如下:
Table组件修改(用useRef绑定容器)
import { useRef } from 'react'; const Table = ({ showCheckbox, isIndeterminate, handleOnChange, isChecked, data, headers, actionRender }) => { // 创建ref指向目标容器 const buttonsContainerRef = useRef(null); return ( <tr> {showCheckbox && <th className="checkbox-table"> <Checkbox indeterminate={isIndeterminate} onChange={handleOnChange} checked={isChecked} disabled={data.every((row) => row.disabled)} /> </th> } {headers.map((header) => <th key={uid()} className="table-cell"> {header.title} </th> )} {actionRender && <th> {/* 用ref绑定目标div */} <div ref={buttonsContainerRef}></div> {/* 仅当容器存在时渲染Portal */} {buttonsContainerRef.current && <ButtonsPortal target={buttonsContainerRef.current} />} </th> } </tr> ); };
Portal组件修改(接收目标容器作为props)
const ButtonsPortal = ({ target }) => { // 目标容器不存在时返回null,避免报错 if (!target) return null; return createPortal(<button>Test</button>, target); };
方案说明
useRef是React官方推荐的组件内DOM元素获取方式,既避免了全局ID查找的耦合问题,又能精准定位当前组件实例内的容器。- 通过
buttonsContainerRef.current的存在判断,确保Portal仅在目标容器挂载到DOM后才渲染,从根源上消除「容器不存在」的报错。 - Portal组件内部的空值判断是双重保险,防止意外场景下传入无效目标。
内容的提问来源于stack exchange,提问作者Anton
相关产品推荐
相关产品推荐

