Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React handleClose() function logging to console but not closing child element

So I’m trying to make a small online store for a personal business.
I’m not very good with React, but I feel like I’ve made some headway and might be able to finish something at least functional, if not very well composed or pretty.

The issue I’m having is with a popup window not closing when the button I’ve placed is pressed.
The button calls a function defined in the function it is called in.
I have a Products.js:

import React from 'react';
import Card from './Card';
import data from './data';
import '../styles/card.css';

const Products = () => {
return (
 <div className="cards-list"/>
{data.map(item => (
 <Card key={item.id} item={item} />
))}
 </div\>
);
};

export default Products;

which contains a series of cards:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import React, { useState, useEffect }  from 'react';
import CardPopup from './CardPopup';
import '../styles/card.css';

const Card = ({ item }) => {
  const [showPopup, setShowPopup] = React.useState(false);
  const [cardImage, setCardImage] = useState(null);

  useEffect(() => {
    import(`../assets/${item.image}`).then((image) => {
      setCardImage(image.default);
    });
  }, [item.image]);

  const handleClick = () => {
    setShowPopup(true);
  };

  const handleClose = () => {
    console.log("handleClose called");
    setShowPopup(false);
  };

  return (
    <div className="card" onClick={handleClick}>
      <img src={cardImage} alt={item.title} className="card-image" />
      <div className="card-view">
        <div className="card-view-text">View</div>
      </div>
      <div className="card-product">{item.title}</div>
      {showPopup && (
        <CardPopup
          handleClose={handleClose}
          title={item.title}
          price={item.price}
          description={item.description}
          image={cardImage}
        />
      )}
    </div>
  );
};

export default Card;

When clicked the card correctly opens this CardPopup.js

import React from 'react';
import { createPortal } from 'react-dom';
import '../styles/CardPopup.css';

const CardPopup = ({ handleClose, title, price, description, image }) => {
  const popupRoot = document.getElementById('popup-root');

  return createPortal(
    <>
      <div className="card-popup-overlay"/>
      <div className="card-popup">
        <img src={image} alt={title} className="card-popup-image" />
        <div className="card-popup-content">
          <div className="card-popup-title">{title}</div>
          <div className="card-popup-price">{price}</div>
          <button className="card-popup-close" onClick={handleClose}>
            X
          </button>
          <div className="card-popup-description">{description}</div>
        </div>
      </div>
    </>,
    popupRoot
  );
};

export default CardPopup;

Inside index.js I’ve appended a dom element for the popup to sit in,

const popupRoot = document.createElement('div');
popupRoot.id = 'popup-root';
document.body.appendChild(popupRoot);

I’ve tried logging handleClose() to the console, and that works correctly, and I tried using functions, const, and classes for Card and CardPopup, but that hasn’t had any impact and I couldn’t get it working with classes.
I’m also not getting any feedback from the console error-wise which is troubling.

I think there’s some basic concept I’m misunderstanding here that is causing this issue.

I’m not asking for someone to fix the code, but if there’s any concepts or react elements I’m blatantly misusing that are causing this error any advice would be greatly appreciated.

>Solution :

If you look at the rendered React tree, your popup is nested within the card.

If you close your popup, your onClick handler of the close button is called first, and afterwards it goes to the parents and calls the onClick handler of the card, opening the popup again.

There are 2 ways to solve this:

Inside the parent, move the popup outside the card:

 return <>
    <div className="card" onClick={handleClick}>
      ...
    </div>
      {showPopup && (
        <CardPopup
          handleClose={handleClose}
          title={item.title}
          price={item.price}
          description={item.description}
          image={cardImage}
        />
      )}
  </>;

Or stop event propagation inside the onClick handler for the closing action

  const handleClose = (e) => {
    e.stopPropagation()
    console.log("handleClose called");
    setShowPopup(false);
  };

See also: https://react.dev/reference/react-dom/createPortal#caveats

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading