Что такое React Portal?
Компоненты
React Portal — механизм рендеринга детей компонента в произвольный DOM-узел вне иерархии родителя, при сохранении их места в React-дереве.
API
import { createPortal } from 'react-dom';
const Modal = ({ children, onClose }) => {
return createPortal(
<div className="overlay" onClick={onClose}>
<div className="modal">{children}</div>
</div>,
document.body, // рендерим в body, а не в родителя
);
};Какую проблему решает
Модалки, тултипы, дропдауны, тосты ломаются, если у кого-то из родителей есть overflow: hidden, z-index-контекст или transform — контент обрезается или оказывается под другими элементами. Portal выносит DOM-узлы в document.body (или отдельный контейнер), и CSS-контекст родителей перестаёт мешать.
React-дерево ≠ DOM-дерево
Хотя DOM-узлы рендерятся в другом месте, в дереве React портал остаётся ребёнком своего компонента:
- контекст работает: модалка видит те же провайдеры (тема, стор);
- события всплывают по React-дереву: клик в модалке дойдёт до React-родителя, даже если в DOM они не вложены;
- жизненный цикл обычный: размонтирование родителя размонтирует и портал.
Нюансы
- Фокус и доступность (aria, focus trap) портал не решает — это остаётся на разработчике или библиотеке (Radix, React Aria).
- Обработчики «клик вне элемента» должны учитывать, что DOM-вложенности нет.
Коротко для собеседования
Portal рендерит детей в другой DOM-узел (обычно document.body) через createPortal(children, container). Нужен для модалок/тултипов, которым мешают overflow и z-index родителей. При этом в React-дереве компонент остаётся на своём месте: контекст доступен, события всплывают как обычно.