Home > OS >  Header Component Stopped Showing When I Used useNavigate Hook
Header Component Stopped Showing When I Used useNavigate Hook

Time:04-04

I've been following along this video series on creating a special type of dropdown hamburger menu. When I got to this part of the video I had to make some changes as I was using react router dom v6 and had learned the the withRouter had been deprecated.

Currently the menu is suppose to disappear once I click on the link to the new page. However after adding in the useNavigate hook my header has completely disappeared. I'm not 100% familiar yet with some of the hooks in react and have found myself stuck on getting my header to appear again and have the menu work. I have put the code I'm working with below, and really could use some guidance on how to get this to work without switching to v5 and going with the video tutorial.

App.js

import "./App.scss";
import Header from "./components/Header";
import MenuWrapper from "./components/MenuWrapper";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

function App() {
  return (
    <Router>
      <div className="App">
        <MenuWrapper>
          <Header />
        </MenuWrapper>
        <div className="container">
          <div className="wrapper">
            <div className="home">
              <Routes>
                <Route exact path="/" element={<Home />} />
                <Route
                  exact
                  path="/opportunities"
                  element={<Opportunities />}
                />
                <Route exact path="/solutions" element={<Solutions />} />
                <Route exact path="/contact-us" element={<Contact />} />
              </Routes>
            </div>
          </div>
        </div>
      </div>
    </Router>
  );
}

function Opportunities() {
  return <p>Discover our numerous opportunities</p>;
}

function Solutions() {
  return <p>Solutions that help you.</p>;
}

function Contact() {
  return <p>Feel free to reach us.</p>;
}

function Home() {
  return (
    <div className="container">
      <div className="wrapper">
        <h5>
          The <b>HAMBRG</b>, is a creative, engineer driven, global agency
          working on advancing the software, advertising and design communities
          to new heights.
        </h5>
      </div>
    </div>
  );
}
export default App;

MenuWrapper.jsx


const withRouter = (Component) => {
  const MenuWrapper = (props) => {
    const history = useNavigate();

    return <Component history={history} {...props} />;
  };

  return MenuWrapper;
};
export default withRouter;

Header.jsx

import { Link } from "react-router-dom";
import Hamburger from "./Hamburger";

const Header = () => {
  //State for menu button
  const [state, setState] = useState({
    initial: false,
    clicked: null,
    menuName: "Menu",
  });

  //State for disabled button
  const [disabled, setDisabled] = useState(false);

  //Use effect for page changes
  useEffect((history) => {
    history.listen(() => {
      setState({ clicked: false, menuName: "Menu" });
    });
  });

  const handleMenu = () => {
    disableMenu();
    if (state.initial === false) {
      setState({
        initial: null,
        clicked: true,
        menuName: "Close",
      });
    } else if (state.clicked === true) {
      setState({
        clicked: !state.clicked,
        menuName: "Menu",
      });
    } else if (state.clicked === false) {
      setState({
        clicked: !state.clicked,
        menuName: "Close",
      });
    }
  };

  //Determine if our menu should be disabled
  const disableMenu = () => {
    setDisabled(!disabled);
    setTimeout(() => {
      setDisabled(false);
    }, 1200);
  };

  return (
    <header>
      <div className="container">
        <div className="wrapper">
          <div className="inner-header">
            <div className="logo">
              <Link to="/">HAMRG.</Link>
            </div>
            <div className="menu">
              <button disabled={disabled} onClick={handleMenu}>
                Menu
              </button>
            </div>
          </div>
        </div>
      </div>
      <Hamburger state={state} />
    </header>
  );
};

export default Header;

Hamburger.jsx

import { Link } from "react-router-dom";

const Hamburger = ({ state }) => {
  let menu = useRef(null);

  useEffect(() => {
    if (state.clicked === false) {
      // close the menu
      menu.style.display = "none";
    } else if (
      state.clicked === true ||
      (state.clicked === true && state.initial === null)
    ) {
      // open the  menu
      menu.style.display = "block";
    }
  });

  return (
    <div ref={(el) => (menu = el)} className="hamburger-menu">
      <div className="menu-secondary-background-color"></div>
      <div className="menu-layer">
        <div className="menu-city-background"></div>
        <div className="container">
          <div className="wrapper">
            <div className="menu-links">
              <nav>
                <ul>
                  <li>
                    <Link to="/opportunities">Opportunities</Link>
                  </li>
                  <li>
                    <Link to="/solutions">Solutions</Link>
                  </li>
                  <li>
                    <Link to="/contact-us">Contact Us</Link>
                  </li>
                </ul>
              </nav>
              <div className="info">
                <h3>Our Promise</h3>
                <p>
                  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
                  do eiusmod tempor incididunt ut labore et dolore magna aliqua.
                  Ut enim ad minim veniam, quis nostrud exercitation ullamco
                  laboris nisi ut aliquip ex ea commodo consequat. Duis aute
                  irure dolor in reprehenderit in voluptate velit esse cillum
                  dolore eu fugiat nulla pariatur. Excepteur sint occaecat
                  cupidatat non proident, sunt in culpa qui officia deserunt
                  mollit anim id est laborum.
                </p>
              </div>
              <div className="locations">
                Location:
                <span>Dallas</span>
                <span>Austin</span>
                <span>New York</span>
                <span>San Francisco</span>
                <span>Beijing</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Hamburger;

CodePudding user response:

A few things here - you don't need the withRouter wrapper at all - all it's really doing is passing the navigate property to a wrapped element (but you're not actually using it). If you need a navigate in the wrapped element, you can just use the hook -

const Header = () => {
    // If you need 'navigate', just use the hook
    const navigate = useNavigate();
};

Now, looking at the final code from the tutorial, it looks like the history was only being used to listen to page changes; you could do the same thing with useLocation -

const Header = () => {
  // ----- 8< -----
  const location = useLocation();

  useEffect(() => {
    setState({ clicked: false, menuName: "Menu" });
  }, [location]);
};

You've also got a bug (potentially?) in the effect in Hamburger.js:

useEffect(() => {
    if (state.clicked === false) {
      // close the menu
      menu.style.display = "none";
    } else if (
      state.clicked === true ||
      (state.clicked === true && state.initial === null)
    ) {
      // open the menu
      menu.style.display = "block";
    }
});

The else if here is incorrect. If state.clicked === true then the if will short circuit; if state.click === false then neither the left side nor the right side will evaluate to true; so in other words, you're just checking:

if (state.clicked === true) {
}

Which might be what you want, or it might be a bug

  • Related