A煤n no tienes acceso a esta clase

Crea una cuenta y contin煤a viendo este curso

Portales: teletransportaci贸n de componentes

18/23
Recursos

Aportes 51

Preguntas 19

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

Damas y Caballeros, bienvenidos a la clase de Portals

Primeramente, para que el bot贸n se mantuviera visible lo que hice fue agregarle un z-index en el css del componente CreateTodoButton de la siguiente forma:

.CreateTodoButton {
  z-index: 1;
}

Y luego para poder cerrarlo lo que hice fue enviarle ademas de setOpenModal el atributo openModal al componente CreateTodoButton para poder crear un condicional

<CreateTodoButton setOpenModal={setOpenModal} openModal={openModal} />
function CreateTodoButton({ setOpenModal, openModal }) {
  const onClickButton = () => {
    if (openModal) {
      setOpenModal(false);
    } else {
      setOpenModal(true);
    }
  };

  return (
    <button className="CreateTodoButton" onClick={() => onClickButton()}>
      +
    </button>
  );
}

para tener en cuenta en react 18

para hacer render del root se usa

import ReactDOM from 'react-dom/client';

pero para hacer render del modal se usa el anterior

import ReactDOM from "react-dom";

espero les sirva el aporte 馃槂

Me da risa la emoci贸n de Juan. Se emociona cuando aparece el modal y luego nos manda el reto 馃槀 馃槀 馃槀.
隆A por el reto!

Al igual que los compa帽eros use el useContext para practicar su uso y en el css agregu茅 el z-index:

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

  const onClickButton = () => {
    setOpenModal(!openModal);
  };

  return (
    <button className="CreateTodoButton" onClick={onClickButton}>
      +
    </button>
  );
}
.CreateTodoButton{
	z-index: 1;
}

Los portales en React sirven para teletransportar componentes a un nodo de HTML distinto al nodo principal de la aplicaci贸n.

Para los que hagan el curso con React 18, si les sale en el navegador el siguiente error ->
"鈥渞eact_dom_client__WEBPACK_IMPORTED_MODULE_1__.createPortal is not a function鈥",
si en su archivo modal.js importaron ReactDOM de 'react-dom/cliente, lo cambian por 鈥 react-dom 鈥

Aqui estan los estilos CSS

.ModalBackground {
  background: rgba(32, 35, 41, .8);
  position: fixed;
  top: -10px;
  left: -10px;
  right: -10px;
  bottom: -10px;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
}

Buenas, yo quise seguir manteniendo la t茅cnica del useContext ya que estamos usando el Provider para enviar las props y state y me esta convenciendo de que es la forma m谩s limpia de mantener controlado y de f谩cil mantenci贸n el pasaje de props y estados.

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

    const handleClick = () => {
        setOpenModal(!openModal);
    }

    return (
        <button  
                className="CreateTodoButton" 
                onClick={handleClick}
        >
            +
        </button>
    );
}

Luego, para mantener por arriba al createTodoButton con la propiedad css z-index tanto en css del Modal y del CreateTodoButton se soluciona sencillamente.

Hola, yo use el react hook useContext

CSS:
z-index: 1;

JS Toggle:
    const { openModal, setOpenModal } = useContext(TodoContext)

    const onClickButton = ()=>{
        !openModal ? setOpenModal(true) : setOpenModal(false)
    }

El caso de uso que se me ocurre para los portales es, teniendo un sitio web est谩tico, de puro HTML, CSS, poder usar React no en una, sino en algunas partes (el root y los portales), y conservar gran parte del HTML original, y sin tener que reconstruir todo el sitio con React.

Si vienes de Vue, esta herramienta es similar a los Slots.

Esta es mi soluci贸n para el reto para cerrar el modal

en el css solo use un z-index: 999; para que el boton est茅 sobre cualquier otro elemento

En JS hice los siguiente

import React, { useContext } from 'react';
import { TodoContext } from '../../Context/TodoContext';
import './CreateTodoButton.css';

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

  const handleClick = () => {
    setOpenModal(!openModal);
  };

  return (
    <>
      <button
        className="CreateTodoButton"
        type="submit"
        onClick={() => handleClick()}
      >
        {openModal ? 'x' : '+'}
      </button>
    </>
  );
};

Portales


驴Qu茅 son?

Una API para renderizar componentes fuera de la jerarqu铆a DOM de su aplicaci贸n.
Incluso podr铆as renderizar cosas en una ventana nueva! 馃槑
.

驴C贸mo se crean?


.

驴Para qu茅?

Perfecto para ocasiones donde los estilos CSS restringen los elementos. Por ejemplo, problemas de apilamiento (z-index) y desbordamiento (overflow).
.

驴C贸mo usarlos?

En lugar de retornar un elemento en el m茅todo render de un componente, retorna un portal.

El componente <Afuera/> se renderizar谩 como descendiente directo de document.body 馃憤馃徎
.

驴Cu谩ndo usarlos?

  • Modales
  • Tooltips
  • Men煤s flotantes
  • Widgets
import React from "react";
import './CreateTodoButton.css'

function CreateTodoButton({setOpenModal, openModal}){
    const onClickButton = () => {
        setOpenModal(!openModal)
    }

    return(
        <button className="CreateTodoButton"
        onClick={onClickButton}>+</button>
    )
}

export { CreateTodoButton }
.CreateTodoButton {
	z-index: 1;
}

Soluci贸n al reto

Modal

import React from "react";
import "./createTodoButton.css";
const CreateTodoButton = ({ setOpenModal, openModal }) => {
  const onClick = () => setOpenModal(!openModal);
  return (
    <button
      className="create-todo-button"
      type="button"
      onClick={onClick}
    >
      +
    </button>
  );
};

export default CreateTodoButton;

css boton de crear

.create-todo-button {
  background-color: #61dafa;
  box-shadow: 0px 5px 25px rgba(97, 218, 250, 0.5);
  border: none;
  border-radius: 50%;
  cursor: pointer;
  font-size: 50px;
  position: fixed;
  bottom: 24px;
  right: 24px;
  font-weight: bold;
  color: #fafafa;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 64px;
  width: 64px;

  transform: rotate(0);
  transition: 0.3s ease;
  z-index: 999;
}

Componente Boton

import React from "react";
import "./createTodoButton.css";
const CreateTodoButton = ({ setOpenModal, openModal }) => {
  const onClick = () => setOpenModal(!openModal);
  return (
    <button
      className="create-todo-button"
      type="button"
      onClick={onClick}
    >
      +
    </button>
  );
};

export default CreateTodoButton;

Para el reto de cerrar el modal simplemente pase el estado actual osea openModal a buttom y lo pase por parametro a su actualizador setOpenModal y lo niegue para que me devolviera el valor contrario.

function CreateTaskButton(props) {
  const onClickButton = () => {
    props.setOpenModal(!props.openModal);
  }
  return (
    <button
      className="CreateTaskButton"
      onClick={onClickButton}
    >
      +
    </button>
  );
}

export { CreateTaskButton };```

Aqu铆 mi sencilla soluci贸n:

en AppIU.js lo primero que hice fue pasarle openModal tambi茅n

<CreateTodoButton 
        setOpenModal={setOpenModal}
        openModal={openModal}
      />

luego en CreateTodoButton

function CreateTodoButton({ openModal , setOpenModal }) {

  const onClickCreateTodoBotton = () => {
    setOpenModal(!openModal);
  };

  return (
    <button 
      className="CreateTodoButton"
      onClick={onClickCreateTodoBotton}
    >
    +
    </button>
    );
}

Mi solucion al reto fue, en CreateTodoButton.css, agregue un z-index: 1 y para hacer que el modal se abra o cierre le pase al componente la propiedad openModal y agregue lo siguiente en CreateTodoButton

const onClickButton = (msg) => {
    props.setOpenModal(!props.openModal);
 };

Lo que hice fue darle a button un z-index de 1, despu茅s pararle las propiedades setOpenModal={setOpenModal} openModal={openModal} a el componente <CreateTodoButton /> y en su index.js decirle que en el evento onclick utilizara props.setOpenModal(!props.openModal) para que vaya alternando entre true o false dependiendo del click.

Juan Dc Ama lo que hace, sin duda.

Esta fue mi soluci贸n:

function CreateTodoButton (){
    const {setOpenModal, openModal} = React.useContext(TodoContext);
    const buttonFunction = () => {
        if (openModal){
            setOpenModal(false)
        } else{
            setOpenModal(true)
        }
    };

    return (
        <button className='button' onClick={()=> buttonFunction()}>
            Add Task
        </button>
    )
}

juan: es hora de terminar nuestra aplicacion 馃槂 馃槂 馃槂 馃槂
yo: esta toda rota mi app juan no mms xd

Para importar las props use useContext y arrow function para simplificar onClick sin perder legibilidad

const { openModal, setOpenModal } = React.useContext(TodoContext);
const onClickButton = () => setOpenModal(!openModal)

Solo agregar z-index: 1;

a las clases del boton, y listo

Reto completado 馃尛

CreateTodoButton --> index.js

function CreateTodoButton(props) {

  const onClickButton = () => {
    props.openModal ? props.setOpenModal(false) : props.setOpenModal(true) 
  }

  return (
    <button className="CreateTodoButton"
      onClick={onClickButton} 
    >
      +
    </button>
  );
}

CreateTodoButton --> css, solo le agrego

  z-index: 1;

Practica

CreateTodoButton.js

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

function CreateTodoButton() {
    const {
        openModal,
        setOpenModal,
    } = React.useContext(TodoContext);
    const onClickButton = () => {
        (!openModal)
            ? setOpenModal(true)
            : setOpenModal(false)
    }
    return (
        <button
            className={ "CreateTodoButton "+ (openModal ? 'active' : '' )}
            onClick={onClickButton}
        >+</button>
    )
}

export {CreateTodoButton};

CreateTodoButton.css

.CreateTodoButton {
  background-color: #61DAFA;
  box-shadow: 0px 5px 25px rgba(97, 218, 250, 0.5);
  border: none;
  border-radius: 50%;
  cursor: pointer;
  font-size: 50px;
  position: fixed;
  bottom: 24px;
  right: 24px;
  font-weight: bold;
  color: #FAFAFA;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 64px;
  width: 64px;

  transform: rotate(0);
  transition: .3s ease;
  z-index: 1;
}

.CreateTodoButton:hover, .CreateTodoButton.active {
  transform: rotate(224deg);
}

Hola, para hacer que el signo de m谩s se vea como una tachita cuando se abra el modal, tienes que agregar este CSS al final del archivo CreateTodoButton.css

.CloseTodoButton {
	transform: rotate(45deg);
}

Ahora solo basta con agregar esta clase cuando el modal est茅 abierto, supongo que hay varias maneras de hacerlo pero yo lo hice as铆 (Archivo CreateTodoButton/index.js)

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

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

	let classNameButton = "CreateTodoButton";
	classNameButton += openModal ? " CloseTodoButton": "";
  return (
		<button
			className={classNameButton}
			onClick={() => setOpenModal(!openModal)}
		>
			+
		</button>
  );
}

export { CreateTodoButton };

Ah铆 mismo podr谩s encontrar como abrir y cerrar el modal de la manera m谩s sencilla posible.

Mi soluci贸n al reto del toggle ser铆a as铆:
1- Cambiar la propiedad z-index de la clase 鈥淐reateTodoButton鈥 en el archivo .css

  z-index: 10; /*o cualquier valor superior al del <div id="modal"></div>

2- Pasar 鈥渙penModal鈥 como props al componente 鈥淐reateTodoButton鈥 en el archivo de AppUI.js

      <CreateTodoButton 
        setOpenModal={setOpenModal} 
        openModal={openModal}
      />

3- Recibir la propiedad 鈥渙penModal鈥 en la definici贸n del componente 鈥淐reateTodoButton鈥 y asignar la negaci贸n del valor de 鈥渙penModal鈥 al momento de llamar a la funci贸n 鈥渟etOpenModal鈥

const CreateTodoButton = ({ openModal, setOpenModal }) => {
  
  const onClickButtom = () => {
    setOpenModal(!openModal)
  }
  ...

Los React Portals te permiten comunicar el nodo principal donde se renderiza nuestra aplicaci贸n con otro nodo generado en HTML. Ambos se pueden comunicar entre s铆 recibiendo cambios en el estado y en las props.

Personalmente prefiero pasarle un componente como prop a los modales. Eg:

import React from "react";
import ReactDOM from "react-dom";

function Modal({ component }) {
	return ReactDOM.createPortal(
		<>{component}</>,
		document.getElementById('modal')
	)
}

export { Modal }

Y usarlo de la siguiente forma:

<Modal component={ <UnFormConMuchosInputs /> } />

A mi gusto queda m谩s legible y reutilizable 馃槃

Dentro de AppUI.js agregue el estado del modal,

      <CreateTodoButton 
        openModal={openModal}
        setOpenModal={setOpenModal}
      />

para recibirlo en props dentro de CreateTodoButton/index.js

    const onClickButton = () => {
        props.setOpenModal(!props.openModal)
    }

donde cambio su valor al contrario del que tiene permitiendo el toogle

Lo que yo hice fue: En AppUI.js agregue esta otra propiedad:
<CreateTodoButton
setOpenModal={setOpenModal}
openModal={openModal}
/>

Luego en el index.js del createButton agregue estas l铆neas,
const onClickButton =()=> {
props.openModal ? props.setOpenModal(false) : props.setOpenModal(true);
}
Para que alterne entre el true y el false,
Y para que el bot贸n se viera, fui al css del mismo y le agregu茅 un z-index: 10;
Para que se superponga a todo el contenido.

Me pareci贸 mejor cerrar el modal cuando el usuario haga click en cualquier parte de la pantalla menos del contenido del modal.

import { TodoContext } from 'context/todoContext';
import { useContext } from 'react';
import ReactDOM from 'react-dom'
import './Modal.css'

function Modal({ children }) {
  const { openModal, setOpenModal } = useContext(TodoContext)
  return ReactDOM.createPortal(
    openModal &&
    <div className="modal-wrapper" onClick={()=> setOpenModal(false)}>
      <div className="modal-content" onClick={(event)=> event.stopPropagation()}>
        {children}
      </div>
    </div>,
    document.getElementById('modal') as Element
  );
}

export default Modal;
/*Modal.css*/
.modal-wrapper{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.8);
  display: flex;
  justify-content: center;
  align-items: center;
}
.modal-content{
  width: 100%;
  max-width: 500px;
  background: #fff;
  border-radius: 5px;
  padding: 20px;
  box-shadow: 0 0 10px rgba(0,0,0,0.5);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

Para que no se cierre el modal al hacer click en el contenido, evitamos la propagaci贸n del evento al padre, con el codigo event.stopPropagation()

MI soluci贸n a los retos, con el button como todo buen programador z-index: 999; XD

Y al Modal

function CreateTodoButton({ openModal, setOpenModal }) {
  const onClickButton = () => {
    !openModal ? setOpenModal(true) : setOpenModal(false);
  };
}

Estuvo genial la clase:DDD

Usando useContext
/CreateTodoButton/CreateTodoButton.jsx

import React from 'react'
import "./CreateTodoButton.css"
import { TodoContext} from './../context/todoContext'
function CreateTodoButton() {
    const { openModal,setOpenModal}=React.useContext(TodoContext)
    const onClickButton = () => {
        setOpenModal(true)     
    }
    return (       
         <button onClick={()=>onClickButton()} className='CreateTodoButton'>+</button>      
    )
}
export   {CreateTodoButton}
Modal/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css'
 import { TodoContext} from './../App/context/todoContext'
const Modal = ({ children }) => {
  const { openModal,setOpenModal}=React.useContext(TodoContext)
    const onClickButton = () => {
        setOpenModal(false) 
    }
  return ReactDOM.createPortal( 
    <div className='modal'>
       <div className="modal-content">        
        <button className="close" onClick={()=>onClickButton()}>&times;</button>
  {children}
  </div></div> ,
  document.getElementById('modal')
);
 
}
export {Modal}

Modal/index.css

.modal {   
  position: fixed;  
  z-index: 1;     
  width: 100%; 
  height: 100%; 
  overflow: auto;     
  background-color: rgba(0,0,0,0.4);    
  top: -10px;
  left: -10px;
  right: -10px;
  bottom: -10px;
  display: flex;
  justify-content: center;
  align-items: center; 
}

.modal-content {
  background-color: #fefefe;
  margin: 15% auto;  
  padding: 20px;
  border: 1px solid #888;
  width: 80%;  
}

.close {
  color: #aaa;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
}

Con CSS para el button utiliz茅 z-index: 2 y en el modal z-index: 1
Para abrir / cerrar el modal utilize el useContext:

const { openModal } = React.useContext(TaskContext);

const onClickButton = () => 
{
	props.setOpenModal( !openModal );
}; 

Este curso es una joya, me encanta todo lo que he aprendido

Mi soluci贸n fue abusar del poderoso useContext

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

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

    return (
        <button 
        className="CreateTodoButton"
        onClick={onClickButton}
        >+</button>
    )
}

export { CreateTodoButton }

Mi soluci贸n fue pasar el estado de openModal y usar un ternario.

function CreateTodoButton({ openModal, setOpenModal }) {
  const onClickButton = () => {
    (openModal)
    ? setOpenModal(false)
    : setOpenModal(true)
  };
  . . .
}

Para el css solo use el z-index

.CreateTodoButton {
  . . .
  z-index: 2;
}

Mi soluci贸n al reto:

function CreateTodoButton({ setOpenModal }) {
  const [isActive, setIsActive] = useState(false);

  const handleClick = () => {
    setOpenModal((openModal) => !openModal);

    setIsActive(!isActive);
  };

  return (
    <button
      className={`CreateTodoButton ${isActive && "OpenModal"}`}
      onClick={handleClick}
    >
      +
    </button>
  );
}

isActive se encarga de manejar el estado de si el modal est谩 abierto o no, si lo est谩, agrega una clase OpenModal al button.

En CreateTodoButton.css agregue una clase la cual, lo 煤nico que hace, es darle un z-index de 1.

.OpenModal {
  z-index: 1;
}

Mi solucion

function Modal({children, setOpenModal}) {
//la funcion handleClick cierra el modal
    function handleClick() {
        setOpenModal(false)
    }
    
    return ReactDom.createPortal(
        <div className="ModalBackground">
            {children} 
            <span onClick={handleClick}>
                X
            </span>
        </div>,
       
        document.getElementById('modal')
    );
}

Una posible soluci贸n para cerrar el Modal, puede ser la siguiente: Al hacer click en cualquier lugar afuera del componente 鈥淧ortaleado鈥, se cierra la modal.
.
Al componente padre (Modal) se le a帽ade el evento de al hacer click, cerrar modal.
.
Modal/index.js

export const Modal = ({ children, setOpenModal }) => {
  const handleClick = () => setOpenModal(false);

  return ReactDOM.createPortal(
    <Wrapper onClick={handleClick}>{children}</Wrapper>,
    document.getElementById('modal')
  );
};

Para impedir que al hacer click dentro del componente 鈥減ortaleado鈥 se cierre, se usa un evento stopPropagation()
.
AppUI.js

<Modal setOpenModal={setOpenModal}>
  <div onClick={(e) => e.stopPropagation()}>Transporteee</div>
</Modal>

Mi soluci贸n:

setOpenModal(!openModal);

Yo lo hice de esta manera, para cerrar el modal puse el 铆cono 鈥淴鈥. Dentro del evento onClick mando a llamar la siguiente funci贸n :

const { setOpenModal } = React.useContext(TodoContext);
const closeModalButton = () => {
      setOpenModal(false);
}

Y por lo pronto mi modal se ve de la siguiente manera:

As铆 esta bien para m铆

Mi solucion al reto de abrir y cerrar el modal es de la siguiente manera:

export const CreateTodoButton = ({setOpenModal, openModal}) => {

    const handleClick = () => {
        setOpenModal(!openModal);
    }

    return (
        <button 
            className="btn-create"
            onClick={handleClick}
        ></button>
    );
}

coloque un z-index en el css del boton

z-index: 1;

y modifique el renombre el onClickButton para llamarlo onToggleButton y
en setOpenModal agregue la negaci贸n de su valor actual.

const onToggleButton = () => {
        props.setOpenModal(!props.openModal);
    }

El uso de modales en los portales es de uso comun

Pregunta de examen:
驴C贸mo creamos un portal en React?