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