React DOMException:无法在“节点”上执行“removeChild”:要删除的节点不是此节点的子节点

neg*_*aro 24 javascript reactjs

如果 state 是 true 播放 youtube 视频,并且它是 false 我想删除 youtube 播放。我的代码如下。

{this.state.isPreViewVideo && <PlayYouTube video_id="ScSn235gQx0" />}
Run Code Online (Sandbox Code Playgroud)

沙箱网址:

https://codesandbox.io/s/xryoz10k6o

繁殖方式:

如果输入表单中包含 4 位字符,则 setState 为“isPreViewVideo: true”,如果小于 false

当 state 为 true 时它工作正常,但是当 state 为 false 时,我会遇到以下错误。

DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
Run Code Online (Sandbox Code Playgroud)

有没有办法避免或解决这个错误?

hen*_*123 30

在 playYouTube.tsx 第 78 行替换<React.Fragment>...</React.Fragment><div>...</div>

Fragments 使您可以对子项列表进行分组,而无需向 DOM 添加额外的节点。

这解释了错误 Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

更多关于这里的片段https://reactjs.org/docs/fragments.html

  • 您能更详细地解释一下为什么会发生这种情况吗?为什么使用 `React.Fragment` 时会抛出错误,而不是使用 `div` 时抛出错误? (5认同)
  • 因为 Fragment 不会向 DOM 添加任何内容。请参阅 React 团队创建的 Codepen https://codepen.io/reactjs/pen/VrEbjE?editors=1000 Fragments(&lt;&gt;&lt;/&gt;) 不会添加到 DOM 中。@sukho 创建的代码沙箱现已更改,但在原始代码沙箱中,片段包装了视频播放器。另外,如果我没记错的话,有一种删除视频播放器的方法。视频播放器的父元素将尝试删除每个子元素,并且由于父元素是 Fragment,因此由于不存在父子关系,因此会失败 (3认同)
  • 这个答案帮助我找到了我的具体问题。就我而言,当我单独渲染/返回 `&lt;i className="fa-circle"/&gt;` 时,会发生此错误。此代码修复了这个问题:`&lt;span&gt;&lt;i className="fa-circle"/&gt;&lt;/span&gt;`。 (2认同)

ama*_*aux 21

Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node如果使用 Google 翻译(或任何其他更改页面 DOM 的插件),也会引发此错误。

这在 Github 问题中有详细说明:https : //github.com/facebook/react/issues/11538


Dmi*_*hin 8

当您使用外部 JS 或 jQuery 插件时,可能会出现此错误。我来说说我的案例吧。

问题描述

在我的 React 项目中,页面上有一些链接,每个链接都会打开一个包含一些信息的模式和一个包含图像的滑块。每个链接在滑块内都有自己的一组图像。但我有单一模式,每个链接都是相同的。模式的数据存储在状态变量中,我在每次链接单击时更改其内容(在每次模式打开时):

const initialData = { title: "", intro: "" }; // here is some empty structure of object properties, we need it for the modalResponse initialization
const [modalData, setModalData] = useState(initialData);
// ...
<div id="MyModal">
    <div className="title">{modalData.title}</div>
    <div className="intro">{modalData.intro}</div>
    <div>{modalData.sliderHtml}</div>
</div>
Run Code Online (Sandbox Code Playgroud)

当我使用打开模态时,setModalData()我会填充modalData一些新数据。里面的 HTML 代码modalData.sliderHtml是这样的结构:

<div class="carousel">
    <div class="item"><img src="first.jpg" /></div>
    <div class="item"><img src="second.jpg" /></div>
    <div class="item"><img src="third.jpg" /></div>
</div>
Run Code Online (Sandbox Code Playgroud)

当模式打开时,我调用一些 jQuery 代码来初始化滑块:

useEffect(() => {
    $('.carousel').initCarousel({
        // some options
    });
}, [modalData]);
Run Code Online (Sandbox Code Playgroud)

然后用户可以关闭模​​式并单击下一个链接。滑块必须由新的图像集填充。但我收到错误:Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

错误原因

该问题的原因是 jQuery 插件在初始化期间更改了 html 的结构。它在父级内部创建一些新块.carousel(向左/向右的箭头、用于导航的点等)。它将所有.item孩子移动到新.items街区内!插件初始化后我得到这样的html结构:

<div class="carousel">
    <div class="dots">...</div>
    <div class="arrows">...</div>
    <div class="items">
        <div class="item"><img src="first.jpg" /></div>
        <div class="item"><img src="second.jpg" /></div>
        <div class="item"><img src="third.jpg" /></div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

当 React 尝试更改其内容时,modalData.sliderHtml它会执行一些神奇的 DOM 操作来删除旧结构。其中一个操作是removeChild方法,但旧.item元素无法在父元素中找到.carousel,因为插件将它们移动到新.items元素中。所以,我们得到了错误。

错误修复

modalData每次关闭模式时,我开始将内容更改回初始数据结构。

useEffect(() => {
    $('#MyModal').on('hidden.bs.modal', function (e) {
        setModalData(initialData);
    })
}, []);
Run Code Online (Sandbox Code Playgroud)

因此,内部的所有 html 结构modalData.sliderHtml都会再次被初始的空数据填充,并且我们在单击新链接时不会收到错误。


zbr*_*zbr 7

问题说明:

什么时候isPreViewVideo是真的,你有这个:

<PlayYouTube video_id="ScSn235gQx0" />
Run Code Online (Sandbox Code Playgroud)

这可能呈现为这样的:

<div> <!-- the root element as rendered by PlayYouTube if isPreViewVideo is truthy -->
  <embed /> <!-- the video player or whatever PlayYouTube renders -->
</div>
Run Code Online (Sandbox Code Playgroud)

现在,如果某些代码通过直接操作 DOM 并移除 root 来移除播放器div,那么您最终会......好吧,什么都没有。

但是在 React 的虚拟 DOM 中,rootdiv还是存在的!因此,当isPreViewVideo出现错误时,React 会尝试将其从真实 DOM 中删除,但由于它已经消失,因此会引发错误。

解决方案:

要扩展@henrik123 的答案 -PlayYouTubediv这样的包装...

<div> <!-- the root element rendered if isPreViewVideo is truthy -->
  <PlayYouTube video_id="ScSn235gQx0" />
</div>
Run Code Online (Sandbox Code Playgroud)

...导致呈现:

<div> <!-- the root element rendered if isPreViewVideo is truthy -->
  <div> <!-- the element as rendered by PlayYouTube -->
    <embed /> <!-- the video player or whatever PlayYouTube renders -->
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

现在,通过删除其根来删除播放器的相同代码div使其看起来像这样:

<div> <!-- the root element rendered if isPreViewVideo is truthy -->
</div>
Run Code Online (Sandbox Code Playgroud)

现在,当isPreViewVideo出现错误时,根存在于 React 的虚拟 DOM 和真实 DOM 中,因此删除它没有问题。它的孩子已经改变了,但在这种情况下 React 并不关心——它只需要删除根。

笔记:

其他 HTML 元素,但div也可能工作。

笔记2:

React.Fragment而不是 a包装是div行不通的,因为React.Fragment它不会向真正的 DOM 添加任何东西。所以有了这个...

<React.Fragment>
  <PlayYouTube video_id="ScSn235gQx0" />
</React.Fragment>
Run Code Online (Sandbox Code Playgroud)

......你最终还是这样:

<div> <!-- the root element as rendered by PlayYouTube if isPreViewVideo is truthy -->
  <embed /> <!-- the video player or whatever PlayYouTube renders -->
</div>
Run Code Online (Sandbox Code Playgroud)

你有同样的问题。

TL;DR 解决方案:

PlayYouTubediv


Ami*_*hah 5

手动关闭按钮后已解决引导程序警报

如果手动关闭引导程序警报错误消息,然后再次提交表单,我会遇到确切的错误。我所做的是用额外的标签包装 AlertError 组件。

import React from "react";

const AlertError = (props) => {
    return (
        <div> // <---- Added this
            <div className="alert alert-custom alert-notice alert-light-danger fade show" role="alert">
                <div className="alert-icon"><i className="flaticon-warning"></i></div>
                <div className="alert-text">There is an error in the form..!</div>
                <div className="alert-close">
                    <button type="button" className="close" data-dismiss="alert" aria-label="Close">
                        <span aria-hidden="true"><i className="ki ki-close"></i></span>
                    </button>
                </div>
            </div>
        </div> // <---- Added this
    );
};

export default AlertError;
Run Code Online (Sandbox Code Playgroud)


Val*_*tin 5

最可能的原因:React 之后修改了 DOM

造成此问题的最可能原因是 React 渲染后,React 以外的其他东西修改了 DOM。

是什么导致了 DOM 突变?

根据受影响用户的情况,可能有几种不同的原因。

每个人

如果您的所有用户都受到影响,那么您(开发人员)可能是罪魁祸首。

原因可能是您正在使用 jQuery 或在 React 之外进行 DOM 操作。

普通用户

如果普通用户受到影响,最可能的原因是 Google Chrome 翻译功能(或Edge Chromium 上的Microsoft 翻译)。

值得庆幸的是,有一个简单的解决方案:<meta>在 HTML 中添加一个标签<head>Google 文档)。

<meta name="google" content="notranslate" />
Run Code Online (Sandbox Code Playgroud)

这也应该禁用 Edge Chromium 上的 Microsoft Translator。

高级用户

如果只有高级用户受到影响,并且他们没有在浏览器上使用翻译功能,那么可能是浏览器扩展或某些用户脚本(很可能由 SpiderMonkey 运行)导致了问题。

更多信息