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

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

Related

NextJS and bootstrap mobile nav

I'm using bootstrap with NextJS for my navbar but have one issue because of the dynamic page changes with React and Next on mobile view the menu stays open after clicking a link and loading new page.
Tried a few ways to try and make it close on page changes but been unsuccessful. What would be best way to achieve this?
import { useEffect } from 'react'
import Link from 'next/link'
import Image from 'next/image'
import { ArrowDownCircle } from 'react-bootstrap-icons'
import logo from '../public/images/logo.gif'
import styles from '../styles/Navbar.module.scss'
const Navbar = () => {
useEffect(() => {
import('bootstrap/js/dist/collapse')
import('bootstrap/js/dist/dropdown')
}, []);
return (
<nav id="navbar" className="navbar navbar-expand-md navbar-light container">
<div>
<Link href="/" prefetch={false}><a className="navbar-brand">
<Image
src={logo}
alt="Logo"
layout="intrinsic"
width={200}
height={50}
priority={true}
/>
</a></Link>
</div>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className={`${styles.navLink} navbar-nav ms-auto`}>
<li className="nav-item">
<Link href="/" prefetch={false}><a className={`${styles.link} nav-link`} aria-current="page">Home</a></Link>
</li>
<li className="nav-item">
<Link href="/about" prefetch={false}><a className={`${styles.link} nav-link`}>About</a></Link>
</li>
<li className="nav-item dropdown">
<a className={`${styles.link} nav-link`} id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">Services <ArrowDownCircle className="ms-1" /></a>
<ul className="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<li><Link href="/web-design"><a className="dropdown-item">Web Design</a></Link></li>
<li><Link href="/web-development"><a className="dropdown-item">Web Development</a></Link></li>
<li><Link href="/ecommerce"><a className="dropdown-item">eCommerce</a></Link></li>
</ul>
</li>
<li className="nav-item">
<Link href="/faq" prefetch={false}><a className={`${styles.link} nav-link`}>FAQ</a></Link>
</li>
<li className="nav-item">
<Link href="/contact" prefetch={false}><a className={`${styles.link} nav-link`}>Contact</a></Link>
</li>
</ul>
</div>
<style jsx>{`
a {
background: none;
}
a:hover {
background: none;
}
`}</style>
</nav>
);
}
export default Navbar;
If anyone still looking for solution in 2022 or later, follow these steps:
Note: This solution was tested on NextJs (Typescript) + Bootstrap v.5.2
Add an id to the button with class navbar-toggler i.e. <button id="navbar-toggler" className="navbar-toggler" ...
In your component class, say Header.tsx
Import useRouter and useEffect:
import { useRouter } from 'next/router'
import { useEffect } from 'react'
and within your component function:
const Header = () => {
const router = useRouter()
useEffect(() => {
const handleRouteChange = (url: String) => {
if (typeof window !== undefined && window.screen.width <= 991.98) { // change the width value according to your navbar breakpoint
const navbar = document.getElementById("navbar-toggler");
if (navbar !== null && !navbar.classList.contains('collapsed')) navbar.click()
}
}
router.events.on('routeChangeComplete', handleRouteChange)
}, [router.events])
return (<> ... other codes </>)
}
export default Header

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

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.

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