tgoop.com/prog_way_blog/338
Create:
Last Update:
Last Update:
Порталы в React
Сталкивались когда-нибудь с проблемой, когда нужно рендерить элемент за пределами текущей DOM-иерархии?
Например, модальные окна, которые не должны быть вложены в основное дерево из-за проблем с позиционированием или всплывающие подсказки, которые всегда должны быть на переднем плане
Для таких задач React предлагает решение — порталы
В документации реакта приведён такой код:
import { createPortal } from 'react-dom';
<div>
<p>Текст расположен в родительском диве</p>
{createPortal(
<p>Текст расположен в document.body </p>,
document.body
)}
</div>
Работает этот код проще простого: элемент, переданный в функцию
createPortal
, будет маунтиться реактом не в родительский див, а в document.body
. Работать это будет с деревом любой вложенностиТакой код будет работать, но он не очень удобен, поэтому многие компонентные библиотеки максимально упрощают порталы для разработчиков и делают подобные компоненты — они есть в Chakra UI, Material UI, Semantic UI и других либах
Но, на самом деле, там нет ничего сложного
Если максимально упростить, то можно прийти к такому варианту:
const Portal = ({ children }: PropsWithChildren) => {
const [container] = useState(() => document.createElement('div'));
useLayoutEffect(() => {
document.body.appendChild(container);
return () => {
document.body.removeChild(container);
};
}, [container]);
return createPortal(children, container);
}
// ...
<Portal>
<p>Текст внутри портала</p>
</Portal>
Тут стоит уточнить две детали:
1. Мы создаём новый
div
внутри useState
, чтобы проще было контролировать порталЕсли мы будем рендерить контент сразу в
document.body
, то можно словить много проблем со стилями и отслеживанием самого порталаИспользуем мы именно useState, чтобы создавать элемент единожды и гарантировано на первый рендер компонента. Элемент создается внутри колбека инициализации состояния — он всегда вызывается единожды на маунт компонента
Как альтернатива, можно обойтись и рефом
2. В
useLayoutEffect
мы привязываем жизненный цикл тега-обёртки к циклу компонента порталаТоже полезно, чтобы лишний раз не задумываться о том, как живёт портал и не создавать ненужных элементов в вёрстке
useLayoutEffect используется вместо useEffect, чтобы обрабатывать портал без лишних мерцаний и более плавно
Вообще, тема разных эффектов и где какой использовать — это отдельная крупная тема, возможно сделаю об этом пост в будущем
Да и всё. Тут компонент на 10 строчек буквально, ничего сверхъестественного. Если вам нужны порталы, то задумайтесь — скорее всего вам хватит такой простой реализации
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
BY progway — программирование, IT
Share with your friend now:
tgoop.com/prog_way_blog/338