I am a total newbie on react. I am trying to use a functional app and wanted to use the function toggleBurgerMenu(). The problem, I am not sure what else I need to define it. Should I use props.toggleBurgerMenu()?
import React from 'react'
import { Link } from "react-router-dom";
import './Header.scss'
const Header = (props) => {
toggleBurgerMenu = () => {
document.querySelector('.navbar-menu').classList.toggle('is-active');
}
return (
<div>
<header>
<nav className="navbar" role="navigation" aria-label="main navigation">
<div id="navbarBasicExample" className="navbar-menu">
<div className="navbar-start">
<Link to="/home" className="navbar-item" onClick={()=> this.toggleBurgerMenu()}>Home</Link>
</div>
</div>
</nav>
</header>
</div>
)
}
export default Header
Appreciate any help. thank you
You need to define your toggleBurgerMenu function like this const toggleBurgerMenu = () => { document.querySelector('.navbar-menu').classList.toggle('is-active'); }. And then you can use it in the onClick Event like this <Link to="/home" className="navbar-item" onClick={toggleBurgerMenu}>Home</Link>
with react the best thing to do is not using document you could use a ref instead, but in this case you can add some state and update the classname
here is an easy example
const Header = (props) => {
/** function to set the state of the button */
const [isActive, setIsActive] = useState(initialState)
return (
<div>
<header>
<nav className="navbar" role="navigation" aria-label="main navigation">
{/**if its true we add is-active class there are several package to this*/}
<div id="navbarBasicExample" className={`navbar-menu ${isActive ? 'is-active' : ''}`}>
<div className="navbar-start">
<Link to="/home" className="navbar-item" onClick={() => setIsActive(prev => !prev.setIsActive)}>Home</Link>
</div>
</div>
</nav>
</header>
</div>
)
}
export default Header
Related
This is my index.html (Where the portal is supposed to lead to)
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="navbarRoot"></div>
<div id="root"></div>
</body>
Here is my navbar component
const Navbar = () => {
const [isOpen , setIsOpen] = useState(false)
const navButtonHandler = () => {
setIsOpen(!isOpen)
}
return (
<>
<nav className='navbar'>
<span><img src={logo} alt='home' className='logo' /></span>
<div className={`menuMask ${isOpen && "open"}`} onClick={navButtonHandler}></div>
<div className={`menuContainer ${isOpen && "open"}`}>
<ul className={`navitems ${isOpen && "open"}`}>
<a href="/" className='home'>
<li>Home</li>
</a>
<a href="/" className='whoWeHelp'>
<li>Who We Help</li>
</a>
<a href="/" className='services'>
<li>Services</li>
</a>
<a href="/" className='about'>
<li>About</li>
</a>
<a href="/" className='caseStudies'>
<li>Case Studies</li>
</a>
<li>
<PrimaryButton link={'https://hadizouhbi.website'}>Client Login</PrimaryButton>
</li>
<li>
<SecondaryButton link={'https://hadizouhbi.website'}>Contact</SecondaryButton>
</li>
</ul>
</div>
<div className={`navToggle ${isOpen && "open"}`} onClick={navButtonHandler}>
<div className='bar'>
</div>
</div>
</nav>
</>
)
}
Where in the code do I use this
{ReactDom.createPortal(<Navbar />, document.getElementById('navbarRoot'))}
Am i doing something wrong? because I have no idea where to put that line however I do think the syntax for that is correct just where to put it is the issue. Any help is greatly appreciated ! I am a beginner to react
If you meant to render the whole NavBar component as a portal then return in the Navbar should be like below.
import { useState } from "react";
import ReactDOM from "react-dom";
const domNode = document.getElementById("navbarRoot");
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const navButtonHandler = () => {
setIsOpen(!isOpen);
};
const navContent = (
<>
<nav className="navbar">
<span>{/* <img src={logo} alt="home" className="logo" /> */}</span>
<div
className={`menuMask ${isOpen && "open"}`}
onClick={navButtonHandler}
></div>
<div className={`menuContainer ${isOpen && "open"}`}>
<ul className={`navitems ${isOpen && "open"}`}>
<a href="/" className="home">
<li>Home</li>
</a>
...
...
</ul>
</div>
<div
className={`navToggle ${isOpen && "open"}`}
onClick={navButtonHandler}
>
<div className="bar"></div>
</div>
</nav>
</>
);
return ReactDOM.createPortal(navContent, domNode);
};
Use Navbar in any other place. In spite of where you try to render it in your component tree, it will always appear in the div with navbarRoot as the id.
export default function App() {
return (
<div className="App">
<Navbar />
</div>
);
}
the code {ReactDom.createPortal(<Navbar />, document.getElementById('navbarRoot'))} goes inside the return statement.
eg:
import Navbar from "component"
function MainPage(){
...
...
return(
<>
...
{ReactDom.createPortal(<Navbar />, document.getElementById('navbarRoot'))}
</>
);
}
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);}}
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
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>
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)
}