React 17 делегирует события к root вместо document
Это не самое громкое изменение React 17, но одно из тех, которые сильнее влияют на совместимость и интеграцию со старым кодом. Если коротко: React перестал вешать обработчики событий на весь document и перенес их ближе к собственному корневому контейнеру.
На практике это было важно не потому, что разработчикам дали новый API, а потому, что смешанные кодовые базы с несколькими корнями React, сторонними скриптами и легаси-обработчиками стали вести себя предсказуемее.
React выполняет делегирование событий автоматически с момента своего первого выпуска. Непосредственно к узлу document он прикрепляет по одному обработчику для каждого типа событий.
Хоть это и улучшает производительность приложения, сообщается о многих проблемах из-за делегирования событий на узле document.
Вот пример одной из таких проблем.
В приведенном ниже примере мы взяли простой компонент React, который выводит в лог событие при нажатии на кнопку Click и отображается в div с идентификатором react-root. Контейнер React DOM завернут в div с id main, у которого есть событие change, содержащее stopPropagation().
// Div событие change содержит stopPropagation()
<div id="main">
// Div где реакт компонент будет отображен
<div id="react-root"></div>
</div>function App() {
const handleClick = (e) => {
console.log(e);
};
return (
<div className="App">
<h1>Example</h1>
<button onClick={handleClick}>Click</button>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('react-root'));Присоединение события change к div#main
document.getElementById("main").addEventListener(
"change",
function (e) {
e.stopPropagation();
},
false
);При нажатии на кнопку событие в консоли не появляется.
Причина в том, что обработчик onChange прикреплён к узлу document, а e.stopPropagation() на div#main перехватывает всплывающее событие раньше.
Чтобы исправить такие проблемы, React 17 больше не подключает обработчики событий на уровне document. Вместо этого он прикрепляет их к корневому контейнеру DOM, в котором отображается дерево React.
Изменения в React 17
После изменений в React 17 события прикрепляются к корневому контейнеру DOM, в котором отображается дерево React. В нашем примере событие будет прикреплено к div с идентификатором react-root. Поэтому наше событие будет инициировано, когда будет нажата кнопка.
Заметка
Релиз-кандидат React 17 можно установить отсюда.
Ознакомьcя с предыдущим обсуждением делегирования событий здесь и pull request здесь.
Итог
Это изменение хорошо показывает, что даже небольшой сдвиг в инфраструктурном поведении React может заметно упростить жизнь на больших и смешанных кодовых базах. Для повседневной разработки это не «новый API», а тихое улучшение предсказуемости.
Если ты поддерживаешь приложение, где React живет рядом с чужим JavaScript или несколькими корнями, именно такие изменения часто экономят больше времени, чем очередной синтаксический сахар.