Los React Portals permiten que algunos componentes salgan del flujo o estructura por defecto de nuestra aplicación. Con ellos podemos crear portales para teletransportar componentes entre diferentes nodos de HTML. Los componentes vivirán en lugares diferentes de la página, lo que evitará muchos problemas de CSS (como z-index
y overflow
), pero React seguirá manteniendo control sobre ellos para comunicarles props y estados.
Con el siguiente gráfico te quedará más claro:
No importa que el portal se encuentre en un nodo del DOM diferente al de la App, características como el event propagation no cambiará y podrás usar a React junto con sus utilidades (manejo de ciclo de vida, context, estado), ya que este lo contempla como un componente más.
Nuestro punto de entrada que por lo general es un index.js
se mantendrá igual.
// index.jsximport React from'react';
import ReactDOM from'react-dom';
import App from'./App';
const rootElement = document.getElementById('app');
const root = ReactDom.createRoot(rootElement);
root.render(<App />);
Pero la magia sucede dentro de App, donde vamos a importar nuestro portal creado con la siguiente utilidad de ReactDOM: ReactDOM.createPortal(componente, nodo)
// App.jsxconst App = () = (
...
<Portal user="Platzinauta" />
)
const Portal = ({ user }) => {
ReactDOM.createPortal(
<div><p>Hi {user}</p></div>,
document.getElmentById("modal")
)
}
Ya tienes todo el contexto necesario para trabajar con React Portals, ahora vamos a ponerlos en practica con un ejemplo practico.
Vamos a crear una app que cuente los clicks que hacemos sobre un botón, pero lo haremos con un portal mientras que vamos a tener otro portal que se va a disparar una vez que hayamos hecho una determinada cantidad de clicks sobre el botón.
Como te lo mencione antes, cada portal funciona en un nodo diferente dentro nuestro HTML por lo que es necesario que tengas estas 3 etiquetas desde el inicio:
<body><divid="app" ></div><divid="modal"></div><divid="advice"></div></body>
Dentro de nuestra App vamos a tener el estado inicial y el botón que será el cual se encargue de aumentar el valor del mismo:
// App.jsxconst App = () => {
const [clicks, setClicks] = React.useState(0)
return(
<divclassName="container" ><buttonclassName="appButton"type="button"onClick={() => setClicks(clicks + 1)}>
Click me!
</button></div>
)
}
Nuestro modal se va a encargar de mostrar los clicks que ha hecho el usuario sobre el botón que se encuentra en al App, por lo que le debemos pasar el estado para que pueda hacer esto:
// modal.jsxconst Modal = ({ clicks }) => {
return ReactDOM.createPortal(
<divclassName="counter" ><h1>Clicks account</h1><p>You click the button {clicks} times</p></div>,
document.getElementById("modal")
)
}
Por otro lado, nuestro componente advice va a recibir los siguientes parámetros:
// advice.jsxconst Advice = ({ clicks, setClicks, message }) => {
return ReactDOM.createPortal(
<divclassName="container-advice"><divclassName="advice"><h2>{message}</h2><p>You clicked {clicks} times</p><buttontype="button"onClick={() => setClicks(0)} >Restart</button></div></div>,
document.getElementById("advice")
)
}
Ya tenemos casi todo, recuerda que los portales por si solos no estarán en nuestra App, sino que debemos importarlos para que puedan funcionar y ser mostrados
En este punto ya podremos agregar una condición para mostrar advice que va a reiniciar la cuenta a 0 y automáticamente desaparecerá, mientras que nuestro Modal solo le deberemos pasar el estado de los clicks de la siguiente manera
const App = () => {
const [clicks, setClicks] = React.useState(0)
return(
<div className="container" >
<button
className="appButton"
type="button"
onClick={() => setClicks(clicks + 1)}>
Click me!
</button>
<Modal clicks={clicks} />
{clicks === 10 &&
<Advice click={clicks}
setState={setClicks} message="You cracked the button :(" />
}
</div>
)
}
En este codepen podrás ver la demo e interactuar con ella.
Con este ejercicio básico, aprendiste que no importa que los portales existan en otra parte distinta del DOM, con React siempre tendrás una conexión para compartir estados y ciclos de vida.
En este pequeño post vimos el uso común de crear un modal y un mensaje flotante que indican el estado de nuestra aplicación, sería interesante el recrear un juego como Portal con esta utilidad ¿No crees?, obviamente tendríamos nuestras limitantes pero sería un reto enorme 👀.
¿Qué más se te ocurre?
Te dejo aquí una colección de cursos para puedas tener un mejor dominio sobre él:
#NuncaParesDeAprender
Excelente post, Leo. Y gracias por las sugerencias de cursos.
Muchas gracias maestro por compartir este blog, lo complementare con el reto de Web Developer 😃