Home > front end >  Close Popover on click in child component
Close Popover on click in child component

Time:09-29

I have a component in which I render a Popover component:

// HeaderMenu.tsx

const HeaderMenu = () => {
  const ShowMenu = () => {
    return (
      <div className={classes.profile}>
        <ul>
          <Notifications />
        </ul>
        <ul>
          <li onClick={handleClose}><Link to={`/profile/${currentUserVar().id}`}>Profile</Link></li>
          <li onClick={handleClose}><Link to='/' onClick={logout}>Logout</Link></li>
        </ul>
      </div>
    );
  };

  return (
    <div>
      <Button onClick={handleClick}>
        <AccountCircleIcon className={classes.profileIcon} />
      </Button>
      <Popover
        id={id}
        open={open}
        anchorEl={anchorEl}
        onClose={handleClose}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'left',
        }}
      >
        <ShowMenu />
      </Popover>
    </div>
  );
};

I can use onClick={handleClose} inside the ShowMenu function but I also have a nested component: Notifications. Inside this component I render a list with some links:

// Notifications.tsx

<Link to={`/profile/${notification.followedUser.id}`}>{notification.followedUser.user_name}</Link>{' '}

How would I call the handleClose function in the HeaderMenu component to close the Popover if a link in the Notifications component has been clicked?

I can use a Reactive variable to trigger a change from the Notifications component (if a link has been clicked) and react to that in the HeaderMenu component by calling the handleClose function. But I was hoping for a better way. Any suggestions?

CodePudding user response:

Add a onRequestClose prop in your Notifications component:

function Notifications({ onRequestClose }) {
  return <div onClick={onRequestClose}>Notifications</div>;
}

const ShowMenu = ({ onRequestClose }) => {
  const classes = makeStyles();

  return (
    <div className={classes.profile}>
      <ul>
        <Notifications onRequestClose={onRequestClose} />
      </ul>
      <ul>
        <li onClick={onRequestClose}>
          <Link to={`/profile/1`}>Profile</Link>
        </li>
        <li onClick={onRequestClose}>
          <Link to="/" onClick={() => {}}>
            Logout
          </Link>
        </li>
      </ul>
    </div>
  );
};

In the parent component, pass the callback down like this:

const classes = makeStyles();
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const id = open ? "simple-popover" : undefined;

const handleClick = (event) => {
  setAnchorEl(event.currentTarget);
};

const handleClose = () => {
  setAnchorEl(null);
};

return (
  <div>
    <Button onClick={handleClick}>
      <AccountCircleIcon className={classes.profileIcon} />
    </Button>
    <Popover
      id={id}
      open={open}
      anchorEl={anchorEl}
      onClose={handleClose}
      anchorOrigin={{
        vertical: "bottom",
        horizontal: "left"
      }}
    >
      <ShowMenu onRequestClose={handleClose} />
    </Popover>
  </div>
);

Live Demo

Codesandbox Demo

  • Related