React Portal移除节点报错:Failed to execute 'removeChild'问题求助
React Portal 点击清除通知触发
removeChild 报错问题解决 问题描述
运行React代码时抛出错误:Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
代码意图为点击body清除所有通知,确保DOM中仅存在一个通知实例。已移除所有Fragment,尝试使用remove和removeChild方法,仍触发报错。
相关代码:
import React, { useEffect, useRef, useId } from "react"; import ReactDOM from "react-dom"; const Modal = (props) => { useEffect(() => { const clearNotifications = () => { var container = document.getElementById("notifications"); if (container) { while (container.firstChild) { container.firstChild.remove(); } } }; const body = document.getElementById("boom-trach"); ///body body.addEventListener("click", clearNotifications, true); return () => { console.log("removed", body); body.removeEventListener("click", clearNotifications, true); }; }, []); const SetBody = () => { return <div id="modal">sss</div>; }; return ReactDOM.createPortal( <SetBody />, document.getElementById("notifications") ); }; export default Modal;
触发报错的React内部代码片段:
if (container.nodeType === COMMENT_NODE) { container.parentNode.removeChild(child); } else { container.removeChild(child); }
疑问:该如何解决此问题?这是否属于React的bug?
解决方案
这不是React的bug,问题根源是直接操作DOM移除了Portal挂载的节点,但React仍持有这些节点的引用,后续React尝试更新或清理时,找不到对应子节点从而抛出错误。
正确修改方案
不要手动操作DOM删除节点,通过React状态控制Portal的显示/销毁,让React自行管理DOM节点,保证虚拟DOM与真实DOM同步:
import React, { useEffect, useState } from "react"; import ReactDOM from "react-dom"; const Modal = (props) => { // 用状态控制Portal是否渲染 const [isVisible, setIsVisible] = useState(true); useEffect(() => { const clearNotifications = () => { // 通过状态更新让React销毁节点 setIsVisible(false); // 若需清空容器内其他非React节点,可在状态更新后异步执行(可选) setTimeout(() => { const container = document.getElementById("notifications"); if (container) { while (container.firstChild) { container.firstChild.remove(); } } }, 0); }; const body = document.getElementById("boom-trach"); body.addEventListener("click", clearNotifications, true); return () => { body.removeEventListener("click", clearNotifications, true); }; }, []); // 状态为false时不渲染Portal if (!isVisible) return null; return ReactDOM.createPortal( <div id="modal">sss</div>, document.getElementById("notifications") ); }; export default Modal;
核心原因
- React Portal的节点由React管理,手动用DOM API移除后,虚拟DOM与真实DOM出现不一致。React在后续渲染周期中会尝试移除它认为存在的子节点,但该节点已被手动删除,因此报错。
- 推荐通过React状态机制控制组件渲染,让React负责DOM的创建与销毁,避免手动操作DOM导致的同步问题。
内容的提问来源于stack exchange,提问作者Crimeira
相关产品推荐
相关产品推荐

