Ручная модификация innerHTML в DOM останавливает слушателей ReactJS

#javascript #dom #reactjs #listener #getelementbyid

#javascript #dom #reactjs #прослушиватель #getelementbyid

Вопрос:

Я изучаю ReactJS и экосистему Node / Express (первые дни для меня). У меня есть элементарный файл ReactJS, включающий определения компонентов и вызовы рендеринга. Он работает, как и ожидалось, сам по себе. Для быстрой / простой отладки вчера я внес следующие изменения в код клиента:

 // Added HTML id to body tag, no other changes whatsoever to DOM/HTML
<body id='body'>...</body>

// In client code, added:
document.getElementById('body').innerHTML  = xhr.responseText;
  

xhr является проверенным, функциональным XMLHttpRequest() . Я делаю запрос, получаю ответ, и он отображается в теле, как и ожидалось. Однако это останавливает все компоненты ReactJS от прослушивания их кнопок и запуска их обработчиков, как определено. Нет обратной связи с консолью или других признаков того, что что-то не так, ReactJS просто выполняет первый рендеринг, как ожидалось, затем молча перестает отвечать.

Если я закомментирую одну строку document.getEle... , все снова начнет работать, включая React и саму xhr себя.

Я знаю, что в ReactJS парадигма заключается не в том, чтобы изменять DOM таким образом, но я не понимаю, почему эта одна строка нарушит всю функциональность ReactJS. Для контекста, вот часть моего кода:

Этот компонент, похоже, работает нормально с document.getEle или без него … закомментирован.

 // Hello World component: manage cookies and display a simple prop
var HelloWorldComponent = React.createClass({

  componentWillMount: function() {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
      if( xhr.readyState == 4 amp;amp; xhr.status == 200 ) {
        // NOTE: this `console.log` gives expected result regardless
        console.log('Performed initial cookie check.  Got response: '   xhr.responseText);
        // document.getElementById('body').innerHTML  = '<div>' xhr.responseText '</div>';
      }
      else {
        console.log('Tried initial cookie check.  Got HTTP response status: '   xhr.status);
      }
    }
    xhr.open('POST', '/cookieCheck');
    xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
    xhr.send();
  },

  render: function() {
    return (
      <h1 id='italic-id' className='red-class'>Hello, {this.props.name}!</h1>
    );
  }
});
  

Этот компонент прерывается, если document.getEle... не закомментирован, в остальном он работает отлично.

 // State component to display simple state
var StateComponent = React.createClass({

  // ReactJS Event: this fails with `document.getEle...` appearing elsewhere in the code
  incrementCount: function() {
    this.setState({
      count: this.state.count   1
    });
  },

  getInitialState: function() {
    return {
      count: 0
    }
  },

  render: function() {
    return (
      <div className='increment-component'>
        <h3 className='red-class'>Count: {this.state.count}.</h3>
        <button onClick={this.incrementCount}>Boing!</button>
      </div>
    );
  }
});
  

Вот как я визуализирую свои компоненты:

 ReactDOM.render(
  <StateComponent/>,
  document.getElementById('state-point')
);
// similar calls for other components as needed
  

Как бы то ни было, я попробовал document.getEle... , как первый запуск JS, как последний запуск JS, и, как вы видите сейчас, как часть компонента ReactJS. Результат один и тот же, независимо от того, где я размещаю его в коде.

Ответ №1:

Я считаю, что причина в том, как innerHTML это работает. Он полностью повторно анализирует и заменяет дочерние узлы DOM (даже если вы используете = для простого добавления новых), поэтому он уничтожает все обработчики событий, ранее прикрепленные к этим узлам DOM, в вашем случае поддерево DOM, «управляемое» React. В вашем случае вам может потребоваться рассмотреть возможность использования insertAdjacentHTML вместо этого.

Из документов MDN (https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML ):

«Он не повторяет элемент, на котором он используется, и, следовательно, не повреждает существующие элементы внутри элемента «.

Попробуйте выполнить следующее:

 document.getElementById('body').insertAdjacentHTML('beforeend', xhr.responseText);