Quando criamos componentes no React, normalmente eles existem dentro da árvore de componentes. Isso é bom, mas às vezes queremos que certas partes de um componente apareçam fora da árvore de componentes ou em algum lugar totalmente diferente.
Este é um requisito comum quando criamos janelas popup modais, que precisam estar acima de todos os outros componentes.
Podemos criá-los dentro de um componente, mas, em última análise, os desejaremos acima de tudo, e tê-los aninhados em muitos componentes pode causar problemas, pois seu z-index
ficará abaixo de tudo o que estiver dentro:
Para resolver esse problema, podemos teletransportar o modal de seu próprio componente para outra parte de nosso modelo usando createPortal
.
Isso nos permite colocar nosso componente em qualquer lugar que desejarmos, como a base da árvore HTML, dentro da tag body
ou dentro de outro elemento.
Mesmo que o elemento exista dentro da árvore de componentes, createPortal
nos dá o poder de colocá-lo onde quisermos.
Para mostrar como os portais funcionam, considere que temos o seguinte código React básico dentro do nosso arquivo App.js
Aqui, queremos que o modal apareça acima de tudo. Assim, criamos um div
chamado #modal-container
. Em última análise, é aqui que queremos que todos os nossos modais entrem:
import logo from './logo.svg'; import './App.css'; import { useState } from 'react' import Modal from './components/Modal.js'; function App() { const [isModalOpen, setIsModalOpen] = useState(false); return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <button onClick={() => setIsModalOpen(!isModalOpen)}> Click to Open Modal </button> <Modal modalState={isModalOpen} onClickEvent={() => setIsModalOpen(!isModalOpen)}> This is Modal Content! </Modal> </header> <div id="modal-container"></div> </div> ); } export default App;
Dentro App.js
, importei um componente chamado Modal
. Este é o nosso componente Modal, que aparecerá sempre que o usuário clicar no botão.
Sempre que isModalOpen
for definido como true usando setIsModalOpen()
, o modal deve aparecer. Caso contrário, desaparecerá.
Também tenho um pouco de CSS para garantir que nossos modais apareçam acima de tudo:
#modal-container { position: absolute; top: 0; left: 0; width: 100%; z-index: 9999; height: 100%; pointer-events: none; } .modal { position: absolute; top: 200px; background: white; border-radius: 4px; left: calc(50% - 100px); width: 200px; }
Criar um portal é muito fácil - há uma função, createPortal()
. Em vez de retornar algum DOM no React, retornamos o Portal
.
createPortal()
aceita dois argumentos - o elemento DOM que queremos retornar - neste caso, o modal - e o elemento DOM para o qual queremos teletransportar nosso elemento DOM.
Portanto, nosso segundo argumento é document.getElementById('modal-container')
, pois queremos colocar todos os nossos modais em #modal-container
:
import { createPortal } from 'react-dom'; function Modal({modalState, onClickEvent}) { if(!modalState) return null; return ( createPortal( <div className="modal"> <button onClick={onClickEvent}>Close Modal</button> <div className="modal-content">Modal Content goes here</div> </div>, document.getElementById('modal-container') ) ); }; export default Modal;
Embora tenhamos teletransportado nosso elemento DOM para modal-container
, ele ainda se comporta como um filho React normal. Como o Portal ainda existe na árvore do React, recursos como o contexto em que o elemento está ainda funcionam da mesma forma.
Também deve ser observado que, embora tenhamos modal-container
e Modal
no mesmo arquivo, o local para o qual você teletransporta seu elemento DOM pode estar em qualquer lugar no seu código React.
Assim, você pode teletransportá-lo para um subcomponente, elemento ou pai completamente diferente em qualquer lugar do DOM. É muito poderoso e útil - então use-o com sabedoria.
Vamos olhar novamente para nosso HTML App.js
:
<!-- .... --> <button onClick={() => setIsModalOpen(!isModalOpen)}> Click to Open Modal </button> <Modal modalState={isModalOpen} onClickEvent={() => setIsModalOpen(!isModalOpen)}> This is Modal Content! </Modal> </header> <div id="modal-container"></div>
Agora, mesmo que o Modal
esteja em nosso cabeçalho, ele aparecerá no #modal-container
sempre que abrirmos o modal usando o botão:
Os portais são uma ferramenta bastante poderosa no React. Eles são uma maneira útil de resolver o problema principal com sistemas baseados em componentes - transportar certos elementos acima de todo o resto.
Sendo assim, espero que você tenha gostado deste guia para portais React. Se você está aprendendo React, sugiro dominar o Javascript primeiro - o que você pode fazer com o meu Javascript Handbook completo.
Tenha um ótimo dia.