Close menu after selecting an anchor link React and Gatsby - reactjs

I have a hamburger nav that uses Gatsby's Link and navigates throughout the website. It works as intended, but if I'm on the same page as an anchor element that I'm clicking, the menu doesn't close. If I close it I can see that it navigated to where it needed to be.
When I add the onClick function then it overwrites the navigation, so the menu closes, but it doesn't navigate anywhere. How to solve this?
import React, { useState } from "react"
import { string } from "prop-types"
import { Link } from "gatsby"
import styles from "./styles.module.less"
const Navbar = ({ siteTitle, navColor }) => {
const [isHidden, showNavigation] = useState(true)
const links = (
<div className={styles.links}>
<Link to="/about">About</Link>
<Link to="/people">People</Link>
<Link to="/#work">Work</Link>
<Link to="/careers">Careers</Link>
<Link to="/contact-us">Contact</Link>
</div>
)
const handleMenuToggle = e => {
e.preventDefault()
showNavigation(!isHidden)
}
let nvColor = navColor ? navColor : "translate"
let logo = navColor ? blackLogo : whiteLogo
return (
<>
<header data-component="Navbar" className={styles.Navbar}>
<Link to="/" className={styles.logo} title={siteTitle}>
<img src={logo} alt={siteTitle} />
</Link>
<a
className={styles.menu}
href="#main-nav"
title="View menu"
onClick={handleMenuToggle}
style={{ color: nvColor }}
>
…
</a>
</header>
<div>
<nav id="main-nav" className={styles.MainNav} hidden={isHidden}>
<div className={styles.blocks}>
<div className={styles.LeftNav}>
<a
onClick={handleMenuToggle}
title="Hide menu"
href="#"
className={styles.close}
>
<img src={close} alt="Hide menu" />
</a>
{links}
</div>
</div>
</nav>
</div>
</>
)
}
Navbar.propTypes = {
siteTitle: string,
}
export default Navbar

You simply need to stop preventing default behavior
const handleMenuToggle = e => {
e.preventDefault() // Remove this line
showNavigation(!isHidden)
}

Related

React - toggleClass on button activate all buttons

I'm trying to make navigation menu similiar to the nav menu in reactjs.org
I'm using Header component and navigation which is objects with links and name. I'm adding class onClick using the state but this toggle all buttons.
import React, { useState } from "react";
import styles from "./index.module.css";
import getNavigation from "../../utils/navigation";
import { Link } from "react-router-dom";
import logo from "../../images/europa-logo.png";
const Header = () => {
const links = getNavigation();
const [isActive, setActive] = useState(false);
const toggleClass = () => {
setActive(!isActive);
};
return (
<div>
<nav className={styles.topnav}>
<div className={styles.pageWrapper}>
<img src={logo} alt="Logo" />
<ul>
{links.map((l, i) => (
<li key={i}>
<Link
className={isActive ? "btn-active" : null}
onClick={toggleClass}
to={l.link}
value={l.title}
>
{l.title}
</Link>
</li>
))}
<li>
{" "}
<div className={styles.social}>
<a href="https://facebook.com">
<FontAwesomeIcon
size="2x"
icon={["fab", "facebook-square"]}
/>{" "}
</a>
<a href="mailto:someone#mail.com">
<FontAwesomeIcon size="2x" icon="envelope" />
</a>
</div>
</li>
</ul>
</div>
</nav>
</div>
);
};
export default Header;
The result is all buttons are activated:
My goal is to activate only the link which is clicked and the first button in nav menu need to be activated by default. What I'm doing wrong?
You can use <NavLink> instead of simple <Link>
is a special version of the that will add styling attributes to the rendered element when it matches the current URL.
<NavLink to="/" activeClassName="active">Link</NavLink>
You can check the docs here:
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/docs/api/NavLink.md
You can define active index and your condition look like this
className={activeIndex === i ? "btn-active" : ""}
Toggle class function:
const [activeIndex, setActiveIndex] = useState(0);
const toggleClass = (i) => {
setActiveIndex(i);
};
and onClick will look like this
onClick={()=>{toggleClass(i);}}

react-router-dom Link does not navigate to the start of target pages

I'm using react-router-dom Link on Home page to navigate to some routes. It works correctly when I'm at the top of Home Page. But when I scroll down the Home and click the Link items in navbar, although it navigates to the specified route, the target page is not displayed from the top. It starts somewhere in the middle of the page.
Here's my navbar:
import React, { Fragment, useState } from "react";
import { Link } from "react-router-dom";
import Fade from "react-reveal/Fade";
import EduLogo from "./resource/edu.png";
import Logo from "./resource/logo.png";
const Navbar = () => {
const [nav, setNav] = useState(false);
const adjustNav = () => {
if (window.scrollY >= 1) {
setNav(true);
document.getElementById("main-nav").style.height = "100px";
document.getElementById("nav-logo").style.height = "30px";
document.getElementById("nav-logo").style.width = "275px";
document.getElementById("nav-edu").style.height = "65px";
document.getElementById("nav-edu").style.width = "200px";
} else {
setNav(false);
document.getElementById("main-nav").style.height = "120px";
document.getElementById("nav-logo").style.height = "37px";
document.getElementById("nav-logo").style.width = "360px";
document.getElementById("nav-edu").style.height = "80px";
document.getElementById("nav-edu").style.width = "238px";
}
};
window.addEventListener("scroll", adjustNav);
return (
<Fragment>
<nav id="main-nav" className={nav ? "main-nav active" : "main-nav"}>
<Fade left>
<div id="main-nav-logo">
<a href="#!" target="_blank">
<img src={EduLogo} alt="" id="nav-edu" />
</a>
<img
src={Logo}
alt=""
id="nav-logo"
/>
</div>
</Fade>
<div className="nav-container">
<Fade bottom cascade>
<ul>
<li id="nav-item">
<Link to="/" className="nav-item">
Home
</Link>
</li>
<li id="nav-item">
<Link to="/members" className="nav-item">
Who We Are?
</Link>
</li>
<li id="nav-item">
<Link to="/research" className="nav-item">
What We Do?
</Link>
</li>
<li id="nav-item">
<Link to="/latest" className="nav-item">
News & Events
</Link>
</li>
</ul>
</Fade>
</div>
</nav>
</Fragment>
);
};
export default Navbar;
Any suggestion?
Thanks
I normally use something like this to make sure that my page is shown from the top whenever it is visited.
React.useLayoutEffect(() => {
window.scrollTo(0, 0);
}, [])
I use the useLayoutEffect hook to apply the window scroll before the browser starts painting.
You can read more about it here

How to close mobile menu in react when click on link?

I am making an app in react. I am facing issue as my mobile menu remains open even after clicking the navbar items. Does anyone know how it can be closed upon clicking on the navbar items?
class Navbar extends Component {
state = { clicked: false};
handleClick = () => {
this.setState({clicked:!this.state.clicked})
};
render () {
return (
<nav className={"NavbarItems"}>
<h1 className={"navbar-logo"}>React<i className={"fab fa-react"}></i></h1>
<div className={"menu-icon"} onClick={this.handleClick}>
<i className={this.state.clicked ? 'fas fa-times': 'fas fa-bars'}></i>
</div>
<ul className={this.state.clicked?'nav-menu active':'nav-menu'}>
{MenuItems.map((item, index) => {
return (
<div key={index}>
<li >
<Link className={item.cName} to={item.url}>
{item.title}
</Link>
</li>
</div>
)
})}
</ul>
<Button><Link className={"nav-button"} to="/contact">Contact Us</Link></Button>
</nav>
)
}
}
export default Navbar;
Could be like this:
<Link to={() => {
this.handleClick();
return '/contact'
}} >Contact Us</Link>

Next JS - Navbar onclick function undefined

I'm trying to make my navigation responsive, so clicking a burger menu icon will then add a class to the nav. Simple concept.
Still new to react and next js.
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useRef, setState, useEffect } from 'react'
const Nav = (props) => {
const router = useRouter()
const isExpanded = () => {
this.state = {
isExpanded: false
}
}
function handleToggle(e) {
e.preventDefault();
this.setState({
isExpanded: !this.state.isExpanded
});
}
return (
<nav>
<div>
<Link href="/">
<a><img src="/img/logo.svg" /></a>
</Link>
<button onClick={e => this.handleToggle(e)} className="nav-icon">
<svg className="fill-current text-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/></svg>
</button>
</div>
<div>
<ul className={`collapsed ${isExpanded ? "is-expanded" : ""}`}>
<li className={router.pathname == "/" ? "active" : ""}>
<Link href="./">
<a>Home</a>
</Link>
</li>
<li className={router.pathname == "/blog" ? "active" : ""}>
<Link href="/blog">
<a>Blog</a>
</Link>
</li>
</ul>
</div>
</nav>
)
}
export default Nav
When I click on the menu burger icon, I then get
TypeError: Cannot read property 'handleToggle' of undefined
Any advice in the right direction would be greatly appreciated. Thank you
You are confusing class based and functional components and not leveraging the advantages of either. Here is a working snippet illustrating a minimal implementation.
It uses React.useState() to declare and set state. Also, when calling named functions event will be passed implicitly so you can simply declare onClick={handleToggle}.
p {
font-family: monospace;
}
<script src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<div id="App"></div>
<script type="text/babel">
const {useState} = React;
const Nav = () => {
const [isExpanded, setIsExpanded] = useState(false);
function handleToggle(e) {
setIsExpanded(prevState => !prevState);
}
return (
<nav>
<div>
<button type="button" onClick={handleToggle} className="nav-icon">
Burger
</button>
</div>
<p>{`isExpanded: ${isExpanded}`}</p>
</nav>
)
}
ReactDOM.render(<Nav />, document.getElementById('App'));
</script>

How to make Hamburger Icon menu function to work with single click in React.js?

I have been following a coding tutorial of making responsive Navbar from Youtube in Html,CSS and JS. While i really wanted to remake it again in react, the hamburger icon works flawlessly previously when i made it in plain Html, CSS and JS Click here to see the example. (Switch the browser in mobile view to see the Hamburger icon)
But when I copied all my code in react (as follows):
import React, { Component } from "react";
import "./style/navbar.css";
import { Link } from "react-router-dom";
class navbar extends Component {
render() {
const navslide = () => {
const burger = document.querySelector(".burger");
const nav = document.querySelector(".nav-links");
const navLinks = document.querySelectorAll(".nav-links li");
burger.addEventListener("click", () => {
nav.classList.toggle("nav-active");
navLinks.forEach((link, index) => {
if (link.style.animation) {
link.style.animation = "";
} else {
link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7 +
0.5}s`;
}
});
burger.classList.toggle("toggle");
});
};
return (
<div>
<nav>
<div className="logo">
<h3>College Facemash</h3>
</div>
<ul className="nav-links">
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/login">Login / Signup</Link>
</li>
</ul>
<div className="burger" onClickCapture={navslide}>
<div className="line1"></div>
<div className="line2"></div>
<div className="line3"></div>
</div>
</nav>
</div>
);
}
}
export default navbar;
it worked well but not not functioning in single click. Instead it did required Double click to function.
Click here to see the demo.(Switch the browser in mobile view to see the Hamburger icon)
So, What changes should i made in order to make my code work flawlessly
Your help would be really valuable to me.
Thanks...
Try like this:
class Navbar extends Component {
const navslide = () => {
const nav = document.querySelector(".nav-links");
const navLinks = document.querySelectorAll(".nav-links li");
nav.classList.toggle("nav-active");
navLinks.forEach((link, index) => {
if (link.style.animation) {
link.style.animation = "";
} else {
link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7 + 0.5}s`;
}
});
burger.classList.toggle("toggle");
});
};
render() {
return (
<div>
<nav>
<div className="logo">
<h3>College Facemash</h3>
</div>
<ul className="nav-links">
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/login">Login / Signup</Link>
</li>
</ul>
<div className="burger" onClick={() => navslide()}>
<div className="line1"></div>
<div className="line2"></div>
<div className="line3"></div>
</div>
</nav>
</div>
);
}
}
why calling burger.addEventListener("click") while your function will run on burger click! this is why it need 2 click to run!
import React, { Component } from "react";
import "./style/navbar.css";
import { Link } from "react-router-dom";
class navbar extends Component {
render() {
const navslide = () => {
const burger = document.querySelector(".burger");
const nav = document.querySelector(".nav-links");
const navLinks = document.querySelectorAll(".nav-links li");
nav.classList.toggle("nav-active");
navLinks.forEach((link, index) => {
if (link.style.animation) {
link.style.animation = "";
} else {
link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7 +
0.5}s`;
}
});
burger.classList.toggle("toggle");
};
return (
<div>
<nav>
<div className="logo">
<h3>College Facemash</h3>
</div>
<ul className="nav-links">
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/login">Login / Signup</Link>
</li>
</ul>
<div className="burger" onClick={navslide}>
<div className="line1"></div>
<div className="line2"></div>
<div className="line3"></div>
</div>
</nav>
</div>
);
}
}
export default navbar;
also i recommend adding state to your component and changing it when ham is clicked!
and then you can change elements classes depending on this state.

Resources