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

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>

Related

Hiding an element after a while in Next.js

I have a header component as a function component. I want show a popup when logo text is clicked. After for a time it should close automatically. I use hooks for state of popup. But set state function doesn't work in setTimeout function. How can fix this?
import Link from 'next/link'
import style from './header.module.css'
const Header = () => {
const [popupOpen, setPopupOpen] = React.useState(false)
return (
<header className={style.header}>
<nav className={style.nav}>
<div
className={style.popupContainer}
onClick={() => {
setPopupOpen(!popupOpen)
console.log(popupOpen)
setTimeout(() => {
console.log(popupOpen)
setPopupOpen(!popupOpen)
console.log(popupOpen)
}, 1000)
}}
>
<span className={style.logo}>Logo</span>
<span
className={`${style.popupText} ${
popupOpen ? style.show : style.hide
}`}
>
Popup Text
</span>
</div>
<ul className={style.ul}>
<li>
<Link href='/'>
<a>.home</a>
</Link>
</li>
<li>
<Link href='/contact'>
<a>.contact</a>
</Link>
</li>
</ul>
</nav>
</header>
)
}
export default Header
Console log:
Let me suggests, this is the same question as:
React - useState - why setTimeout function does not have latest state value?
const _onClick = () => {
setPopupOpen(!popupOpen);
setTimeout(() => {
setPopupOpen(popupOpen => !popupOpen)
}, 2000);
};
Its happening because setPopupOpen is asynchronous. So by the time setPopupOpen(!popupOpen) is called it has same value as onClick first setPopupOpen(!popupOpen) so eventually when it called both setPopup doing same state update i.e both updating as false. Better way is to usesetPopupOpen callback function to update the value. I added this code.
import { useState } from "react";
import Link from "next/link";
import style from "./style.module.css";
const Header = () => {
const [popupOpen, setPopupOpen] = useState(false);
const toggle = () => {
setPopupOpen((prev) => !prev);
};
const onClick = () => {
setPopupOpen(!popupOpen);
setTimeout(() => {
toggle();
}, 1000);
};
return (
<header className={style.header}>
<nav className={style.nav}>
<div className={style.popupContainer} onClick={onClick}>
<span className={style.logo}>Logo</span>
{popupOpen && (
<span
className={`${style.popupText} ${
popupOpen ? style.show : style.hide
}`}
>
Popup Text
</span>
)}
</div>
<ul className={style.ul}>
<li>
<Link href="/">
<a>.home</a>
</Link>
</li>
<li>
<Link href="/contact">
<a>.contact</a>
</Link>
</li>
</ul>
</nav>
</header>
);
};
export default function IndexPage() {
return (
<div>
<Header />
</div>
);
}
Here is the demo: https://codesandbox.io/s/pedantic-haibt-iqecz?file=/pages/index.js:0-1212

How to get side drawer to close when clicking on link

I have a navbar component that opens a side drawer when clicking the burger menu on a mobile device. But when I click a link it goes to the 'page' but the side drawer does not close.
Do I have to add a click event to every link to change the toggle state to false? That seems like the wrong, long winded approach.
const NavBar = (props) => {
const [toggle, setToggled] = useState(false);
const toggleTrueFalse = () => setToggled(!toggle);
return (
<nav>
<div className="logo">
<h4>The nav</h4>
</div>
<ul className={toggle ? "nav-links nav-active" : "nav-links"}>
<li>
<Link to="/" activeclassname="active">
Home
</Link>
</li>
<li>
<Link to="/faq" activeclassname="active">
FAQ
</Link>
</li>
<li>
<Link to="/contact" activeclassname="active">
Contact us
</Link>
</li>
</ul>
<div
className={toggle ? "burger linetoggle" : "burger"}
onClick={toggleTrueFalse}
>
<div className="line1"></div>
<div className="line2"></div>
<div className="line3"></div>
</div>
</nav>
);
};
export default NavBar;
you can have link array and map it :
const links = []
\\in render
links.map((link,index)=>{
return(<li key=index onclick={toggleTrueFalse}>
<Link to={link.to} activeclassname="active">
{link.txt}
</Link>
</li>)
}

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.

Trying to toggle between icon to text on my navigation using React

I have some code down and it works but my problem is that it changes all of the icons at the same time when i scroll over just one. I only want the icon that I hover over to change, so any help would be appreciated.
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {isHovered: false};
this.toggleHover = this.toggleHover.bind(this);
}
toggleHover() {
this.setState(prevState => ({isHovered: !prevState.isHovered}));
}
render() {
return (
<section className="info-section">
<div className="logo">
MATT
</div>
<div className="info-box">
<ul className="nav-links">
<li onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>
{this.state.isHovered
? <a className="home active" href="/">Home</a>
: <a className="home active" href="/"><FontAwesomeIcon icon={faHome} /></a>
}
</li>
<li onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>
{this.state.isHovered
? About
: <FontAwesomeIcon icon={faUser} />
}
</li>
Maybe you can try to use CSS.
<ul className="nav-links">
<li>
<a href="/">
<span>Home</span>
<FontAwesomeIcon icon={faHome} />
</a>
</li>
<li>
<a href="/about">
<span>Home</span>
<FontAwesomeIcon icon={faUser} />
</a>
</li>
...
a {
span {
display: none;
}
&:hover {
span {
display: block;
}
/* hide the icon base on their html tag or class */
i {
display: none;
}
}
}
If you really want to handle this through Javascript (which I'm not suggesting), you can try this.
class App extends Component {
state = {
hover: ""
};
handleMouseEnter = key => {
this.setState({ hover: key });
};
handleMouseLeave = () => {
this.setState({ hover: "" });
};
render() {
const { hover } = this.state;
return (
<ul>
<li
onMouseEnter={() => this.handleMouseEnter("home")}
onMouseLeave={this.handleMouseLeave}
>
<a href="/">
{hover === "home" ? <span>Hover Home</span> : <span>Home</span>}
</a>
</li>
<li
onMouseEnter={() => this.handleMouseEnter("about")}
onMouseLeave={this.handleMouseLeave}
>
<a href="/about">
{hover === "about" ? <span>Hover about</span> : <span>about</span>}
</a>
</li>
</ul>
);
}
}

Close menu after selecting an anchor link React and Gatsby

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)
}

Resources