'Why do createPortal renders the whole component?
I have a problem with the createPortal function. When I use the "Modal", then by changing the states, the whole "Modal" component will be rendered. Can you help me how to avoid this? So when I comment out the Modal wrap in the Cart component (as I did it below), it works as I expected, but with the Modal wrap, when the states are changed, not the component will be re-rendered, but always the whole Modal Component
Here is my Modal component with createPortal function:
import React from 'react';
import { createPortal } from 'react-dom';
import { useState } from 'react';
import './modal.scss';
export default function Modal({ children, onClick }) {
const BackDrop = () => {
return <div className='backdrop' onClick={onClick}></div>;
};
const Modal = () => {
return (
<div className='modal'>
<div className='content'>{children}</div>
</div>
);
};
return (
<>
{createPortal(<BackDrop />, document.getElementById('modal'))}
{createPortal(<Modal />, document.getElementById('modal'))}
</>
);
}
The Cart component which uses the Modal component:
import React, { useEffect } from 'react';
import Modal from '../UI/Modal';
import './cart.scss';
import { useCartContext } from '../../store/CartContext';
import CartItem from './CartItem';
export default function Cart({ onHideCart }) {
const { cart, totalPrice, updateTotalPrice, addToCartOne, removeFromCartOne } = useCartContext();
useEffect(() => {
updateTotalPrice();
}, [totalPrice, cart]);
const onAddHandler = (id) => {
addToCartOne(id);
updateTotalPrice();
};
const onRemoveHandler = (id) => {
removeFromCartOne(id);
updateTotalPrice();
};
return (
// <Modal onClick={onHideCart}>
<div>
<ul className='cart-items'>
{cart.map((item, idx) => (
<CartItem
key={item.id}
name={item.name}
price={item.price}
amount={item.amount}
onAdd={onAddHandler.bind(null, item.id)}
onRemove={onRemoveHandler.bind(null, item.id)}
/>
))}
</ul>
<div className='total'>
<span>Total Amount</span>
<span>$ {totalPrice.toFixed(2)}</span>
</div>
<div className='actions'>
<button className='button--alt' onClick={onHideCart}>
Close
</button>
<button className='button'>Order</button>
</div>
</div>
// </Modal>
);
}
So by changing the amount with + and - buttons, the html element with id modal, always renders, it's flashes in the devtools... but when I comment out the Modal wrap in the Cart component, there is no flashes by modal ID. I hope it makes sense.
Solution 1:[1]
The problem was with the two custom element inside of the Cart element. When I return
createPortal(
<>
<div className='backdrop' onClick={onClick}></div>
<div className='modal'>
<div className='content'>{children}</div>
</div>
</>,
document.getElementById('modal')
)
instead of this:
<>
{createPortal(<BackDrop />, document.getElementById('modal'))}
{createPortal(<Modal />, document.getElementById('modal'))}
</>
Then there is no problem with rendering.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Dharman |

