'Hide/Show elements in React

So I have this code wherein there's a button in the Header.jsx file that once clicked, it will display the content of the Notification.jsx file. The problem here is, I don't exactly know how can I display the content of Notification.jsx in index.js. I tried using conditional statements but to no avail and is it possible to hide the h1 element once the button is clicked?

Header.jsx

import React from "react";
import { Button } from "@mui/material";
import { IconButton } from "@mui/material";
import NotificationsIcon from "@mui/icons-material/Notifications";
import SearchIcon from "@mui/icons-material/Search";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import FullNotifList from "./FullNotifList"
export default function Header() {
  const [anchorEl, setAnchorEl] = React.useState(null);
  const open = Boolean(anchorEl);
  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };
  const handleClose = () => {
    setAnchorEl(null);
  };
  return (
    <div>
      <Button
        id="basic-button"
        aria-controls={open ? "basic-menu" : undefined}
        aria-haspopup="true"
        aria-expanded={open ? "true" : undefined}
        onClick={handleClick}
      >
        <IconButton>
          <NotificationsIcon />
        </IconButton>
      </Button>
      <Menu
        id="basic-menu"
        anchorEl={anchorEl}
        open={open}
        onClose={handleClose}
        MenuListProps={{
          "aria-labelledby": "basic-button",
        }}
      >
        {/* Button needs to be clicked in order to display Notification.jsx */}
        <Button variant="contained">Notification Center</Button> 
        <MenuItem onClick={handleClose}>Profile</MenuItem>
        <MenuItem onClick={handleClose}>My account</MenuItem>
        <MenuItem onClick={handleClose}>Logout</MenuItem>
      </Menu>

      <IconButton>
        <SearchIcon />
      </IconButton>
    </div>
  );
}

Notification.jsx

import React from "react";

export default function Notification(){
    return(
        <div>
            <ul>
                <li> Hello </li>
                <li> Hello </li>
                <li> Hello </li>
                <li> Hello </li>
            </ul>
        </div>
    )
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import reportWebVitals from './reportWebVitals';
import Header from './Header'
import './index.css'
import Footer from './Footer';
import Notification from './Notification';

export default function Page(props) {
    const [isClicked, setIsClicked] = React.useState(false)
    function showHide(e) {
        setIsClicked(true)
    };

    return(
        <div className='main'>
            <Header onClick={showHide}/>
                {isClicked && <Notification />}
                <h1> Sample body </h1>
            <Footer />
        </div>
    )
}

ReactDOM.render(
    <Page />,
  document.getElementById('root')
);

Here is the sandbox link: https://codesandbox.io/s/friendly-darkness-9u5s22?file=/src/index.js



Solution 1:[1]

You were right to use conditional rendering, however your conditional logic isn't working because you're assuming your Header component has an event listener.

Events listeners are an important part of Javascripts history, but are more or less abstracted out with library's like Material UI. More on that in a minute, first let me present to you the quick and easy solution; in your index.js, utilize event listeners with vanilla html:

<div onClick={showHide}>
  <Header />
  {isClicked && <Notification />}
  <h1> Sample body </h1>
  <Footer />
</div>

You'll also want to use a boolean switch in cases like these:

function showHide(e) {
  setIsClicked(!isClicked);
}

To listen to events, earlier versions used attachEvent:

element.attachEvent('onclick', function() { /* do stuff here*/ });

Modern browsers now support useEventListener:

element.addEventListener('click', function() { /* do stuff here*/ }, false);

Here you can attach event listeners to as many elements as you want (memory permitting), including the users window element. That final parameter is a relic of pre-universal Javascript browser support, so now capture events and bubbling events are both supported. The default (false) is set to bubbling, where events 'bubble up' the DOM tree from the target node. More information on that here.

You can target your event listeners in Header.jsx to handle your events manually, and learn a little about JS event propagation. Since this is React, we want to utilize the useEffect, and useCallback hook to stop infinite rendering. Then well pass the callback function as props, so you can 'interact' with the Header component from index.js:

<div className="main">
  <Header callback={showHide} />
  {isClicked && <Notification />}
  <h1> Sample body </h1>
  <Footer />
</div>

then in Header. jsx:

import { useCallback, useEffect } from "react";

export default function Header(props) {

  const handleClick = useCallback((event) => {
    props.callback(event);
  }, [props]);

  useEffect(() => {
    window.addEventListener("click", handleClick);
  }, [handleClick]);

...

Note that the window element will target the whole component. To add events to individual html elements with id="header-component", use:

let element = document.getElementById("header-component");

Now for the third and I'd say best solution, utilizing React's props design pattern. Header.jsx:

export default function Header(props) {
  return(
    <Button onClick={props.callback}>Display Notifications</Button> //here we use the MUI button, but you can also use div or any other event listening element
    ...
  );
}

and same thing again in index.js:

<div className="main">
  <Header callback={showHide} />
  {isClicked && <Notification />}
  <h1> Sample body </h1>
  <Footer />
</div>

In this case, you can use different callback functions to attach as many events as you want to one element, while relying on React to do the heavy lifting.

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