Cuando creamos componentes en React, normalmente existen dentro del árbol de componentes. En general, esto está bien, pero a veces queremos que ciertas partes de un componente aparezcan fuera del árbol de componentes , o en algún lugar completamente diferente.
Este es un requisito común cuando creamos ventanas emergentes modales, que deben estar por encima de todos los demás componentes.
Podemos crearlos dentro de un componente, pero finalmente los querremos por encima de todo lo demás, y tenerlos anidados dentro de muchos componentes puede causar problemas ya que su z-index
caerá por debajo de lo que sea que estén dentro:
Para resolver este problema, podemos teletransportar el modal fuera de su propio componente y dentro de otra parte de nuestra plantilla usando createPortal
.
Esto nos permite colocar nuestro componente en cualquier otro lugar que deseemos, como la base del árbol HTML, dentro de la etiqueta del body
o dentro de otro elemento.
Aunque el elemento existe dentro del árbol de componentes, createPortal
nos da el poder de ponerlo donde queramos.
Para mostrarle cómo funcionan los portales, tenga en cuenta que tenemos el siguiente código React básico dentro de nuestro archivo App.js
Aquí, queremos que el modal aparezca encima de todo lo demás. Como tal, hemos creado un div
llamado #modal-container
. En última instancia, aquí es donde queremos que entren todos nuestros modales:
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 de App.js
, he importado un componente llamado Modal
. Este es nuestro componente Modal, que aparecerá cada vez que el usuario haga clic en el botón.
Cada vez que isModalOpen
se establece en verdadero usando setIsModalOpen()
, debería aparecer el modal. De lo contrario, desaparecerá.
También tengo un poco de CSS para garantizar que nuestros modales aparezcan encima de todo lo demás:
#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; }
Crear un portal es bastante fácil: hay una función, createPortal()
. En lugar de devolver algo de DOM en React, devolvemos el Portal
.
createPortal()
acepta dos argumentos: el elemento DOM que queremos devolver, en este caso, el modal, y el elemento DOM al que queremos teletransportar nuestro elemento DOM.
Entonces, nuestro segundo argumento es document.getElementById('modal-container')
, ya que queremos poner todos nuestros modales en #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;
Aunque teletransportamos nuestro elemento DOM a modal-container
, todavía se comporta como un niño React normal. Dado que el Portal aún existe en el árbol de React, características como el contexto en el que se encuentra el elemento aún funcionan de la misma manera.
También se debe tener en cuenta que aunque tenemos modal-container
y Modal
en el mismo archivo, el lugar al que teletransporta su elemento DOM puede estar en cualquier parte de su código React.
Por lo tanto, podría teletransportarlo a un subcomponente, elemento o padre completamente diferente en cualquier lugar del DOM. Es bastante poderoso y útil, así que úsalo sabiamente.
Miremos hacia atrás en nuestro HTML de 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>
Ahora, aunque Modal
se encuentra en nuestro encabezado, aparecerá en #modal-container
cada vez que abramos el modal usando el botón:
Los portales son una herramienta bastante poderosa en React. Son una forma útil de resolver el problema principal con los sistemas basados en componentes: transportar ciertos elementos por encima del resto.
Como tal, espero que haya disfrutado de esta guía de portales de React. Si está aprendiendo React, le sugiero que primero domine Javascript, lo que puede hacer con mi Manual de Javascript completo.
Qué tengas un lindo día.