Порталы
Порталы предоставляют первоклассный способ визуализации дочерних элементов в узле DOM, который существует вне иерархии DOM родительского компонента.
ReactDOM.createPortal(child, container)
Первый аргумент (child) - это любой визуализируемый дочерний элемент React, например элемент, строка или фрагмент. Второй аргумент (контейнер) является элементом DOM.
использование
Обычно, когда вы возвращаете элемент из метода рендеринга компонента, он монтируется в DOM как дочерний элемент ближайшего родительского узла:
,render() {
// React mounts a new div and renders the children into it
return (
<div>
{this.props.children}
</div>
);
}
Однако иногда полезно вставить дочерний элемент в другое место в DOM:
render() {
// React does *not* create a new div. It renders the children into `domNode`.
// `domNode` is any valid DOM node, regardless of its location in the DOM.
return ReactDOM.createPortal(
this.props.children,
domNode
);
}
Типичным вариантом использования порталов является случай, когда родительский компонент имеет переполнение: скрытый стиль или стиль z-index, но вам нужно, чтобы дочерний элемент визуально «вырвался» из своего контейнера. Например, диалоговые окна, карты наведения и подсказки.
Замечания:
При работе с порталами помните, что управление фокусировкой клавиатуры становится очень важным.
Для модальных диалогов, убедитесь, что каждый может взаимодействовать с ними, следуя правилам WAI-ARIA.
Событие пузырится через порталы
Хотя портал может находиться где угодно в дереве DOM, он ведет себя как обычный дочерний элемент React во всех других отношениях. Такие функции, как контекст, работают одинаково независимо от того, является ли дочерний портал порталом, поскольку портал все еще существует в дереве React независимо от положения в дереве DOM.
Это включает в себя барботирование событий. Событие, инициируемое внутри портала, будет распространяться на предков в содержащем дереве React, даже если эти элементы не являются предками в дереве DOM. Предполагая следующую структуру HTML:
<html>
<body>
<div id="app-root"></div>
<div id="modal-root"></div>
</body>
</html>
Родительский компонент в # app-root мог бы перехватить неперехваченное всплывающее событие от узла-брата # modal-root.
// These two containers are siblings in the DOM
const appRoot = document.getElementById('app-root');
const modalRoot = document.getElementById('modal-root');
class Modal extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
// The portal element is inserted in the DOM tree after
// the Modal's children are mounted, meaning that children
// will be mounted on a detached DOM node. If a child
// component requires to be attached to the DOM tree
// immediately when mounted, for example to measure a
// DOM node, or uses 'autoFocus' in a descendant, add
// state to Modal and only render the children when Modal
// is inserted in the DOM tree.
modalRoot.appendChild(this.el);
}
componentWillUnmount() {
modalRoot.removeChild(this.el);
}
render() {
return ReactDOM.createPortal(
this.props.children,
this.el,
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {clicks: 0};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// This will fire when the button in Child is clicked,
// updating Parent's state, even though button
// is not direct descendant in the DOM.
this.setState(state => ({
clicks: state.clicks + 1
}));
}
render() {
return (
<div onClick={this.handleClick}>
<p>Number of clicks: {this.state.clicks}</p>
<p>
Open up the browser DevTools
to observe that the button
is not a child of the div
with the onClick handler.
</p>
<Modal>
<Child />
</Modal>
</div>
);
}
}
function Child() {
// The click event on this button will bubble up to parent,
// because there is no 'onClick' attribute defined
return (
<div className="modal">
<button>Click</button>
</div>
);
}
ReactDOM.render(<Parent />, appRoot);
Перехват событий, всплывающих из портала в родительском компоненте, позволяет разрабатывать более гибкие абстракции, которые по своей природе не зависят от порталов. Например, если вы визуализируете компонент <Modal />, родительский объект может захватывать свои события независимо от того, реализован ли он с использованием порталов.
Новый контент: Composer: менеджер зависимостей для PHP , R программирования