Portals

Что такое Порталы? 🤔

Порталы позволяют рендерить дочерние элементы в DOM-узел, который находится вне DOM-иерархии родительского компонента.

ReactDOM.createPortal(child, container);
  1. child — это любой React-компонент, который может быть отрендерен, такой как элемент, строка или фрагмент. ( это то что будет вставлено)
  2. container — это DOM-элемент. (это куда будет втавлено)

Когда Использовать? ✍🏻

Порталы прекрастно подходят для таких задач как -

  • модальные окна,
  • подсказки,
  • попапы,
  • всплывающме элементы
Интересно

Через портал можно открыть новую вкладку браузера и отрисовать что либо из родителя и синхронизовать там данные с родителем

Пример Модального окна с использованием React.createPortal

1import React from "react";
2import ReactDOM from "react-dom";
3
4const Modal = ({ children, open }) => {
5 if (open) {
6 return ReactDOM.createPortal(
7 <div className="modal">{children}</div>,
8 document.body
9 );
10 }
11
12 return null;
13};

Portal будет возвращен из render если переменная open true.

import Modal from './modal'
const App = ({children})=> {
const [open,setOpen] =React.useState(false)
render() {
return (
<div>
<div>
<button onClick={() => setOpen(rue)}>open</button>
</div>
<Modal open={open}>
<div>
<h1>Hello from portal</h1>
<button onClick={() => setOpen(false)}>close</button>
</div>
</Modal>
</div>
)
}
}
  • Когда переменная open = false - наш DOM выглядит как обычно:
<html>
<head>
....
</head>
<body>
<div id="root" />
...
</body>
</html>
  • Когда переменная open = true - в DOM добавляется наш елемент с модальным окном:
<html>
<head>
....
</head>
<body>
<div id="root" />
...
<div class="modal">
<div>
<h1>Hello from portal</h1>
<button>close</button>
</div>
</div>
</body>
</html>
Важно

Tак как в качестве контейнера мы указали document.body наш новоиспеченный элемент добавился в body - потому что Portal монтируется в DOM как дочерний элемент ближайшего родительского узла. Это очень важный момент который нужно помнить, если вы делаете всплывающие окна или поздсказки то контейнером для них должен быть не document.body, а элемент на который они указывают.

Всплытие событий через порталы

Несмотря на то, что портал может быть где угодно в дереве DOM, он ведет себя как обычный дочерний элемент React во всех отношениях.

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

Важно

Событие, созданное внутри портала, будет распространяться к предкам в объемлющем дереве React, даже если они не являются предками в дереве DOM.

Почитать 📚

Практика 👩‍💻👨‍💻

Создать компонент <Tooltip/>

const App = () => {
return (
<Tooltip content="Tooltip for hello">
<p>Hello</p>
</Tooltip>
);
};
  • При вызове события onMouseEnter на дочерний элемент компонента Tooltip, должна показаться подсказка из property content

  • При событии onMouseEnter подсказка должна быть скрыта

  • Компонент Tooltip должен использовать ReactDOM.createPortal

Edit this page on GitHub