Приведи пример использования React Portal.
Компоненты
Классический пример портала — модальное окно, которое должно отрисоваться поверх всего, независимо от CSS-контекста родителей.
Пример: модалка
import { createPortal } from 'react-dom';
const Modal = ({ open, onClose, children }) => {
if (!open) return null;
return createPortal(
<div className="overlay" onClick={onClose}>
<div className="modal" onClick={(e) => e.stopPropagation()}>
{children}
<button onClick={onClose}>Закрыть</button>
</div>
</div>,
document.body, // рендер вне иерархии родителя
);
};Использование:
const ProductCard = ({ product }) => {
const [open, setOpen] = useState(false);
return (
<div className="card"> {/* у карточки overflow: hidden */}
<button onClick={() => setOpen(true)}>Подробнее</button>
<Modal open={open} onClose={() => setOpen(false)}>
<ProductDetails product={product} />
</Modal>
</div>
);
};Что демонстрирует пример
- Без портала модалка обрезалась бы
overflow: hiddenкарточки и проигрывала бы соседям по z-index. С порталом её DOM — прямой ребёнок body. - В React-дереве Modal остаётся внутри ProductCard: видит контекст (тему, стор), а клики из модалки всплывают в React-родителей, поэтому работает
stopPropagation. - Состояние
openживёт у владельца — портал не меняет поток данных.
Другие типичные применения
- Тултипы и поповеры (позиционирование относительно viewport).
- Тосты/уведомления в углу экрана (отдельный
<div id="toasts">). - Дропдауны внутри скроллируемых контейнеров с overflow.
Коротко для собеседования
Типовой пример — модалка через createPortal(jsx, document.body): DOM рендерится вне родителя (не режется overflow/z-index), но в React-дереве компонент остаётся на месте — контекст доступен, события всплывают. Так же делаются тултипы, тосты и дропдауны.