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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 11:05:16