React DOMException: не удалось выполнить «removeChild» на «узле»: удаляемый узел не является дочерним элементом этого узла

Если состояние истинно для воспроизведения видео на YouTube, и оно ложно, я хотел бы удалить воспроизведение на YouTube. МОЙ код выглядит следующим образом.

{this.state.isPreViewVideo && <PlayYouTube video_id = "ScSn235gQx0" />}

URL песочницы:

https://codesandbox.io/s/xryoz10k6o

Метод воспроизведения:

Если в форму ввода включены 4-значные символы, "isPreViewVideo: true" по setState и если оно меньше 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.

есть ли способ избежать или устранить эту ошибку?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
30
0
39 740
8

Ответы 8

В playYouTube.tsx строку 78 заменить <React.Fragment>...</React.Fragment> с <div>...</div>

Fragments let you group a list of children without adding extra nodes to the 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?

tonix 03.11.2019 09:39

Да почему так происходит? Если это произойдет без какой-либо предсказуемой причины, то должны ли мы прекратить использование фрагментов??

K. D. 13.02.2020 10:30

Потому что фрагменты ничего не добавляют в DOM. См. этот Codepen, созданный командой React codepen.io/reactjs/pen/VrEbjE?editors=1000. Фрагменты (<></>) не добавляются в DOM. Код-песочница, созданная @sukho, теперь изменена, но в исходной код-песочнице есть Фрагменты, обертывающие видеоплеер. Также, если я правильно помню, был метод удаления видеоплеера. Родительский элемент видеоплеера попытается удалить каждый дочерний элемент, и, поскольку родительский элемент был фрагментом, это не удастся, поскольку не было отношений родитель-потомок.

henrik123 13.02.2020 12:13

Этот ответ помог мне перейти к моей конкретной проблеме. В моем случае эта ошибка произошла, когда я рендерил/возвращал <i className = "fa-circle"/> в одиночку. Этот код исправляет это: <span><i className = "fa-circle"/></span>.

mojmir.novak 14.12.2020 18:20

Комментарий @mojmir.novak был очень полезен для меня, так как решает проблему. Можете ли вы сказать мне, почему это работает с <span/>, но не с <i/>?

Stéphane de Luca 06.07.2021 14:30

@StéphanedeLuca Я не уверен. Это похоже на ошибку или, возможно, манипулирование javaScript потрясающим шрифтом, но у меня не было времени это проанализировать.

mojmir.novak 09.07.2021 15:34

В моем случае у меня было модальное окно на основе jQuery в DOM (fomantic-ui/semantic-ui), и оно было заключено во фрагмент. Простое создание <><div> решило эту проблему. wtf, я потратил больше часа, пытаясь решить эту проблему!

anarchist912 21.09.2021 10:27

У меня были такие же проблемы с аудиотегом, и я сохранил этот тег в двух вложенных div, и теперь он работает

Эта ошибка Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node также может возникать, если используется Google Translate (или любой другой плагин, который изменяет DOM страницы).

Это подробно описано в этом выпуске Github: https://github.com/facebook/реагировать/issues/11538.

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

исправить:

   unmountContainer() {
      // macro task
      setTimeout(() => {
        // refs
        if (containerEle) {
          // receive removed node
          // eslint-disable-next-line no-unused-vars
          let removedChild = document
            .querySelector('.page__wrapper')
            .removeChild(containerEle);
        }
      });
    }

Объяснение проблемы:

Когда isPreViewVideo правда, у вас есть это:

<PlayYouTube video_id = "ScSn235gQx0" />

Вероятно, это выглядит примерно так:

<div> <!-- the root element as rendered by PlayYouTube if isPreViewVideo is truthy -->
  <embed /> <!-- the video player or whatever PlayYouTube renders -->
</div>

Теперь, если какой-то код удалит плеер, напрямую манипулируя DOM и удалив корень div, вы получите... Ну, ни с чем.

Но в виртуальном DOM React корень div все еще существует! Поэтому, когда isPreViewVideo становится ложным, React пытается удалить его из реального DOM, но, поскольку он уже ушел, выдается ошибка.

Решение:

Чтобы расширить ответ @ henrik123 - обернуть PlayYouTube таким div...

<div> <!-- the root element rendered if isPreViewVideo is truthy -->
  <PlayYouTube video_id = "ScSn235gQx0" />
</div>

... заставляет это отображать:

<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>

Теперь тот же код, который удаляет игрока, удаляя его корень div, делает его таким:

<div> <!-- the root element rendered if isPreViewVideo is truthy -->
</div>

Теперь, когда isPreViewVideo становится ложным, корень существует как в виртуальной DOM React, так и в реальной DOM, поэтому нет проблем с его удалением. Это дети изменились, но React в этом случае все равно - ему просто нужно удалить корень.

Примечание:

Другие элементы HTML, кроме div, тоже могут работать.

Заметка 2:

Обтекание React.Fragment вместо div не сработает, потому что React.Fragment ничего не добавляет к реальному DOM. Так что с этим...

<React.Fragment>
  <PlayYouTube video_id = "ScSn235gQx0" />
</React.Fragment>

... вы все равно получите это:

<div> <!-- the root element as rendered by PlayYouTube if isPreViewVideo is truthy -->
  <embed /> <!-- the video player or whatever PlayYouTube renders -->
</div>

И у вас такая же проблема.

TL; DR решение:

Оберните PlayYouTubediv.

Для меня ваше решение в сочетании с обертыванием всего кода внутри return с помощью <></> вместо решения проблемы div. +1

Rolandas Dundulis 15.12.2021 03:05

Эта ошибка может возникнуть при использовании внешних плагинов 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>

Когда я открываю модальное окно с помощью 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>

Когда модальное окно открылось, я вызываю некоторый код jQuery для инициализации слайдера:

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

Затем пользователь может закрыть модальное окно и щелкнуть следующую ссылку. Ползунок должен быть заполнен новым набором изображений. Но я получаю сообщение об ошибке: 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>

Когда React пытается изменить содержимое modalData.sliderHtml, он выполняет некоторые волшебные операции DOM для удаления старой структуры. Одной из таких операций является метод removeChild, но старые элементы .item не могут быть найдены внутри родительского элемента .carousel, потому что плагин переместил их внутрь нового элемента .items. Итак, получаем ошибку.

Исправление ошибок

Я начал менять содержимое modalData обратно на структуру initialData каждый раз, когда модальное окно закрывается.

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

Таким образом, вся html-структура внутри modalData.sliderHtml снова заполняется исходными пустыми данными, и мы не получаем ошибку при переходе по новой ссылке.

В одном месте нашего кода было что-то вроде этого:

render() {
 if (el) return <div />

 return '';
}

После замены '' на ноль все работает без ошибок.

SOLVED for bootstrap alert after manually close button

У меня была точная ошибка, когда я закрывал сообщение об ошибке предупреждения о начальной загрузке, если оно было там вручную, а затем снова отправлял форму. что я сделал, так это обернул компонент 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;

Другие вопросы по теме