No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Aprende Inglés, Programación, AI, Ciberseguridad y más a precio especial.

Antes: $249

Currency
$209
Suscríbete

Termina en:

2 Días
3 Hrs
4 Min
23 Seg
Curso de React.js

Curso de React.js

Juan David Castro Gallego

Juan David Castro Gallego

¿Qué son los React Portals?

24/34
Recursos

Aportes 23

Preguntas 7

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

No me funcionaba el ReactDOM.createPortal, buscando en la documentación de React me indicaba que se escribe diferente, cabe aclarar que es la versión 18:

Esa técnica con las manos para abrir portales me parece conocida! 🤣

Lo que hice para abrir y cerrar el Modal fue pasarle el contexto al componenete createTodoButton y al hacerle click que cambie su estado de false a true y a la inversa:

function CreateTodoButton() {
    const {
        setOpenModal,
        openModal,
    } = React.useContext(TodoContext)

    return (
        <button
            className={"newTodo"}
            onClick={() => {setOpenModal(!openModal)}} 
        >
        <FaPlus 
            className="icon"
        />
        </button>
    );
}

¿Para qué sirven los portales?

Los portales nos permiten ubicar un componente hijo dentro del conjunto de componentes que se renderizan en el nodo html principal del DOM, generalmente el id = “root”, pero hacer que aparezcan en un **nodo **fuera de la jerarquía del DOM. Esto permite una mayor facilidad a la hora de maquetar y estilizar componentes que aparecen y desaparecen en el renderizado de nuestra página como los modales (ventanas).

Gracias a los portales, por ejemplo, podemos ubicar a nuestro componente <Modal> luego del conjunto de componentes que tenemos en la AppUI como <TodoCounter/>, <TodoSearch/> o <CreateTodoButton/>, pero el renderizado se hará en el div del nodo html que nosotros indiquemos, osea fuera del “root”. Esto trae como ventaja por ejemplo poder estilizar fácilmente el modal para que aparezca por encima del resto de componentes.

Aquí esta la documentación más reciente de la API del DOM createPortal.

React DOM API : createPortal - React Docs

Mi solución fue un if en el componente de button usando el contexto.

Según lo que entendí, es así.

Se siente mucho más ordenado usando useContext, ¡gran clase JuanDC!

createPortal recibe 3 parametros:

  • Children: cualquier cosa que pueda ser renderizada con react.
  • domNode: nodo(s)
  • (opcional) Key: un string o número único que para ser usado como portal

Aquí tienen esta página por si les interesa no tener que hacer un modal desde el principio, sino usar los que ofrece bootstrap https://react-bootstrap.netlify.app/docs/components/modal/.

Reto del modal

Seria algo asi, si se finjan tego declarado mi useState en false como dijo el profesor porque quiero que mi modal desde el principio este cerrado, luego en mi etiqueta de button, con el manejador de onClick hago que el estado cambie a true y como la condicion abajo dice cada vez que openModal sea verdadero muestrame ese componente. Cabe resaltar que en mi componente de modal tengo un boton llamado closeModal el cual cuando quiero cerrar el modal lo actualizo a false y este completa la accion.

const [openModal, setOpenModal] = useState(false);
<button className={styles.btn} onClick={() => setOpenModal(true)}>
	<div></div>
        <div></div>
        <div></div>
</button>
{openModal ? <Modal closeModal={() => setOpenModal(false)} />

Les comparto la documentación: createPortal

Otra manera de hacerlo es con la importación directa de createPortal sin utilizar ReactDOM

import React from 'react'
import { createPortal } from 'react-dom'
export const ModalMessage = ( {children}) => {
  return (
    createPortal(
      <div>
        {children}
      </div>,
      document.body
    )
  )
}

En React 18, las funciones como `createPortal` aún se exportan desde `react-dom`, pero debes importarlas directamente en lugar de acceder a ellas a través de un objeto `ReactDOM` importado. Si estás utilizando React 18, deberías importar `createPortal` directamente de `react-dom` así: `import React from "react";` `import { createPortal } from "react-dom"; // Importación directa de createPortal` `function Modal({children}) {` ` return createPortal(` `
` ` {children}` `
,` ` document.getElementById('modal')` ` );` `}` `export { Modal };` *Cortesía de ChatGPT*

No me renderizaba el portal en la consola, para esto realicé la importacion de createPortal de esta manera:

import React from "react";
import { createPortal } from "react-dom";

function Modal({ children }) {
    return createPortal(
        <div className="Modal">
            {children}
        </div>,
        document.getElementById('modal')
    );
}

export { Modal };

Por otra parte para que abrir y cerrar el portal con el createButton hice el siguiente codigo:

import React from 'react';
import './CreatTodoButton.css';
import { TodoContext } from '../TodoContext';


function CreateTodoButton() {
    const {
        openModal,
        setOpenModal,
      } = React.useContext(TodoContext);

    return(
        <button 
        className="CreateTodoButton" 
        onClick={
            (e) =>
                {setOpenModal(!openModal)}
        }>+</button>
    )
};

No sabia de esta funcionalidad, genial genial!

Yo lo hice de esta manera, desde AppUI.

 {openModal && createPortal(
        <ModalNewTodo openModal={openModal} />,
        document.body
        )}

Con MUI

export const ModalNewTodo = ( ) => {
const {searchValue,setSearchValue,openModal, setOpenModal} = useContext(TodoContext);
const [tareaValue, setTarea] = useState(searchValue);
const handleCancel = () => {
setOpenModal(!openModal);
setSearchValue(’’);
}
const handleAccept = () => {
setOpenModal(!openModal);
}
return (
<>
<Dialog open={openModal} onClose={handleCancel} fullWidth>
<DialogTitle>Nueva tarea</DialogTitle>
<DialogContent>
<DialogContentText>
{searchValue ? ’ ¿Está seguro que quiere registar esta tarea?’ : ’ Escribe la tarea que deseas realizar’}
</DialogContentText>
<TextField
autofocus
margin="dense"
id="txt_tarea"
label="Descripción"
type="text"
fullWidth
variant="standard"
value={tareaValue}
onChange={(event) => {
setTarea(event.target.value);
}}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleCancel}>Cancelar</Button>
<Button onClick={handleAccept}>Aceptar</Button>
</DialogActions>
</Dialog>
</>
)
}

Button
export const CreateTodoButton = () => {
const {setOpenModal,openModal} = useContext(TodoContext);

const handleClickAdd = () =>{
setOpenModal(!openModal);
}
return (
<Stack sx={{width:100, mt:1}}>
<Button variant=“contained” startIcon={<AddIcon />} size=“small” onClick={handleClickAdd}>Agregar</Button>
</Stack>
)
}

Referencia createPortal

Una consulta, si va a haber un formulario, no seria mejor dentro del mismo agregar dos botones, uno para que al guardar se cierre el modal y otro boton para cerrar el modal en el caso de que no quieran agregar todos, sino lo presionen por error?
estoy pensando en hacer el reto asi

Para aquellos que quieran eliminar el div interno con la clase modal para que asi solo tengan un solo div y no dos, pueden remplazar el div del componente Modal por un React.Fragment, recuerden se usa con esta etiquetas <>{children}\.
function CreateTodoButton() { *const* { setOpenModal, openModal, } = React.useContext(TodoContext); *return* ( \<button onClick={() => setOpenModal(!openModal)} className='CreateTodoButton'>+\</button> )} ```js function CreateTodoButton() { const { setOpenModal, openModal, } = React.useContext(TodoContext); return ( <button onClick={() => setOpenModal(!openModal)} className='CreateTodoButton'>+</button> )} ```
**mi solución:** function CreateTodoButton() { *const* { setOpenModal, openModal, } = React.useContext(TodoContext); *return* ( \<button onClick={() => setOpenModal(!openModal)} className='CreateTodoButton'>+\</button> )}
Aquí comparto como me quedo el reto y tambien funciona el cerrado por la x ![](https://static.platzi.com/media/user_upload/image-39d78aad-ecb6-49c7-b6c5-cd8243cc76a7.jpg)

Juan sos el mejor profe del mundo!