make dropdown menu visible using react - reactjs

I have following code with navbar and dropdown in it. All I want is to make the dropdown visible but I am not able to do it. What should I do. I have my code as
Header.jsx
import React, { useState } from 'react'
import { Link } from 'react-router-dom';
const Header = () => {
const [isVisible, setIsVisible] = useState(false);
return(
<div className="menu-container">
<nav className="nav">
<ul className="nav__menu">
<li className="nav__menu-item">
<Link to="Aboutus">About us</Link>
</li>
<li className="nav__menu-item">
<Link to="Myaccount">My account</Link>
</li>
<li className="nav__menu-item">
<Link to="Featured Product">Featured Product</Link>
</li>
<li className="nav__menu-item">
<Link to="WishList">WishList</Link>
</li>
<li className="nav__menu-items">
<Link to="Order Tracking">Order Tracking</Link>
</li>
<li className="nav__menu-items">
<Link to="English">English</Link>
{isVisible && (
<div>
<Link to className="box">English</Link>
<Link to className="box">German</Link>
<Link to className = "box">Spanish</Link>
</div>
)}
</li>
<li className="nav__menu-items">
<Link to="USD">USD</Link>
{isVisible && (
<div>
<Link to className="box">USD</Link>
<Link to className="box">INR</Link>
<Link to className="box">GBP</Link>
</div>
)}
</li>
</ul>
</nav>
</div>
)
}
export default Header
The code in the English and USD contains the dropdown but I am not able to make it possible visible. How can I make it visible.

Try this.
import React, { useState } from 'react'
import { Link } from 'react-router-dom';
const Header = () => {
const [isVisible, setIsVisible] = useState(false);
const toggle = () => {setIsVisible(!isVisible)}
return(
<div className="menu-container">
<nav className="nav">
<ul className="nav__menu">
<li className="nav__menu-item">
<Link to="Aboutus">About us</Link>
</li>
<li className="nav__menu-item">
<Link to="Myaccount">My account</Link>
</li>
<li className="nav__menu-item">
<Link to="Featured Product">Featured Product</Link>
</li>
<li className="nav__menu-item">
<Link to="WishList">WishList</Link>
</li>
<li className="nav__menu-items">
<Link to="Order Tracking">Order Tracking</Link>
</li>
<li className="nav__menu-items">
<Link to="English" onClick={toggle}>English</Link>
{isVisible && (
<div>
<Link to className="box">English</Link>
<Link to className="box">German</Link>
<Link to className = "box">Spanish</Link>
</div>
)}
</li>
<li className="nav__menu-items">
<Link to="USD" onClick={toggle}>USD</Link>
{isVisible && (
<div>
<Link to className="box">USD</Link>
<Link to className="box">INR</Link>
<Link to className="box">GBP</Link>
</div>
)}
</li>
</ul>
</nav>
</div>
)
}
export default Header

You don't change the value of isVisible in your code.
You should use setIsVisible function to set the new value of isVisible to true or false, as our want.

Related

How do I create a portal for this navbar (React)

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

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

How Can I set State in stateless Function, in a nested Function?

I know that I can't change the state in a stateless function when the function is nested, though I am only this far away to set the state in order for the page work as I would want. I want to keep this as a functional component. The issue is below I want to set the language under this function, or any other way works I know how to do this with Class component, though unless there will be 10 votes to do that would prefer to stay with functional.
function changeTounge(e) {
console.log("Write something!!");
console.log(e.currentTarget.dataset.id);
console.log(e.currentTarget.dataset.value);
//setLanguage({ iso2: "lv", speak: "Latviešu" });
}
the full code is:
import React, { useState } from "react";
import { Link } from "react-router-dom";
export function PrimaryNav() {
const [language, setLanguage] = useState({ iso2: "us", speak: "English" });
return (
<div className="primary-nav">
<ul className="navigation">
<li className="active">
<Link to="/">Home</Link>
</li>
<li className="has-child">
Opportunities
<div className="wrapper">
<div id="nav-homepages" className="nav-wrapper">
<ul>
{OpsOption("RealEstate", "Real Estate")}
{OpsOption("Vehicles", "Vehicles")}
{OpsOption("JobSearch", "Job Search")}
{OpsOption("PersonalCompany", "Personal Company")}
{OpsOption("Inves`enter code here`tInIdea", "Invest In Idea")}
</ul>
</div>
</div>
</li>
<li>
<Link to="/contact">Help & Support</Link>
</li>
<li className="has-child language">
{ActiveLanguage(language.iso2, language.speak)}
<div className="wrapper">
<div id="nav-languages" className="nav-wrapper">
<ul>
{LanguageOption("English", "us")}
{LanguageOption("British", "gb")}
{LanguageOption("Latviešu", "lv")}
{LanguageOption("Estonia", "ee")}
{LanguageOption("Lithuania", "lt")}
{LanguageOption("Russian", "ru")}
{LanguageOption("Deutch", "de")}
{LanguageOption("French", "fr")}
</ul>
</div>
</div>
</li>
</ul>
</div>
);
}
function LanguageOption(label, classLabel) {
return (
<li
onClick={changeTounge.bind(this)}
data-id={label}
data-value={classLabel}
>
<Link to="#nav-locations">
<span className={"flag-icon flag-icon-" + classLabel}></span>
{" "}
{label}
</Link>
</li>
);
}
function changeTounge(e) {
console.log("Write something!!");
console.log(e.currentTarget.dataset.id);
console.log(e.currentTarget.dataset.value);
//setLanguage({ iso2: "lv", speak: "Latviešu" });
}
function OpsOption(pageLink, label) {
return (
<li>
<Link to={"/" + pageLink}>{label}</Link>
</li>
);
}
function ActiveLanguage(iso2, activeLanguage) {
return (
<a href="#nav-languages">
<span className={"flag-icon flag-icon-" + iso2}></span> {activeLanguage}
</a>
);
}
export default PrimaryNav;
Try nesting the components inside of the main component, they'll be able to access and set its state. This is still a functional pattern here.
The other option would be to add a prop to your children components, and pass in the setLanguage function through that prop.
Also, you don't need the changeTounge.bind.this in functional react :D. In general, if you're using this at all in functional react... that's a red flag.
import React, { useState } from "react";
import { Link } from "react-router-dom";
const PrimaryNav = () => {
const [language, setLanguage] = useState({ iso2: "us", speak: "English" });
const changeTounge = (e) => {
console.log("Write something!!");
console.log(e.currentTarget.dataset.id);
console.log(e.currentTarget.dataset.value);
setLanguage({ iso2: "lv", speak: "Latviešu" });
}
const OpsOption = (pageLink, label) => {
return (
<li>
<Link to={"/" + pageLink}>{label}</Link>
</li>
);
}
const ActiveLanguage = (iso2, activeLanguage) => {
return (
<a href="#nav-languages">
<span className={"flag-icon flag-icon-" + iso2}></span> {activeLanguage}
</a>
);
}
const LanguageOption = (label, classLabel) => {
return (
<li
onClick={changeTounge}
data-id={label}
data-value={classLabel}
>
<Link to="#nav-locations">
<span className={"flag-icon flag-icon-" + classLabel}></span>
{" "}
{label}
</Link>
</li>
);
}
return (
<div className="primary-nav">
<ul className="navigation">
<li className="active">
<Link to="/">Home</Link>
</li>
<li className="has-child">
Opportunities
<div className="wrapper">
<div id="nav-homepages" className="nav-wrapper">
<ul>
{OpsOption("RealEstate", "Real Estate")}
{OpsOption("Vehicles", "Vehicles")}
{OpsOption("JobSearch", "Job Search")}
{OpsOption("PersonalCompany", "Personal Company")}
{OpsOption("Inves`enter code here`tInIdea", "Invest In Idea")}
</ul>
</div>
</div>
</li>
<li>
<Link to="/contact">Help & Support</Link>
</li>
<li className="has-child language">
{ActiveLanguage(language.iso2, language.speak)}
<div className="wrapper">
<div id="nav-languages" className="nav-wrapper">
<ul>
{LanguageOption("English", "us")}
{LanguageOption("British", "gb")}
{LanguageOption("Latviešu", "lv")}
{LanguageOption("Estonia", "ee")}
{LanguageOption("Lithuania", "lt")}
{LanguageOption("Russian", "ru")}
{LanguageOption("Deutch", "de")}
{LanguageOption("French", "fr")}
</ul>
</div>
</div>
</li>
</ul>
</div>
);
}
export default PrimaryNav;
There are probably tidier ways to do some of this, but this seems to work:
import React, { useState } from "react";
import { Link } from "react-router-dom";
export function PrimaryNav() {
const [language, setLanguage] = useState({ iso2: "us", speak: "English" });
return (
<div className="primary-nav">
<ul className="navigation">
<li className="active">
<Link to="/">Home</Link>
</li>
<li className="has-child">
Opportunities
<div className="wrapper">
<div id="nav-homepages" className="nav-wrapper">
<ul>
{OpsOption("RealEstate", "Real Estate")}
{OpsOption("Vehicles", "Vehicles")}
{OpsOption("JobSearch", "Job Search")}
{OpsOption("PersonalCompany", "Personal Company")}
{OpsOption("Inves`enter code here`tInIdea", "Invest In Idea")}
</ul>
</div>
</div>
</li>
<li>
<Link to="/contact">Help & Support</Link>
</li>
<li className="has-child language">
{ActiveLanguage(language.iso2, language.speak)}
<div className="wrapper">
<div id="nav-languages" className="nav-wrapper">
<ul>
{LanguageOption("English", "us", setLanguage)}
{LanguageOption("British", "gb", setLanguage)}
{LanguageOption("Latviešu", "lv", setLanguage)}
{LanguageOption("Estonia", "ee", setLanguage)}
{LanguageOption("Lithuania", "lt", setLanguage)}
{LanguageOption("Russian", "ru", setLanguage)}
{LanguageOption("Deutch", "de", setLanguage)}
{LanguageOption("French", "fr", setLanguage)}
</ul>
</div>
</div>
</li>
</ul>
</div>
);
}
function LanguageOption(label, classLabel, setLanguage) {
return (
<li
onClick={(event) => changeTounge(event, setLanguage, label, classLabel)}
data-id={label}
data-value={classLabel}
>
<Link to="#nav-locations">
<span className={"flag-icon flag-icon-" + classLabel}></span>
{" "}
{label}
</Link>
</li>
);
}
function changeTounge(e, setLanguage, label, classLabel) {
console.log("Write something!!");
console.log(e.currentTarget.dataset.id);
console.log(e.currentTarget.dataset.value);
setLanguage({ iso2: classLabel, speak: label });
}
function OpsOption(pageLink, label) {
return (
<li>
<Link to={"/" + pageLink}>{label}</Link>
</li>
);
}
function ActiveLanguage(iso2, activeLanguage) {
return (
<a href="#nav-languages">
<span className={"flag-icon flag-icon-" + iso2}></span> {activeLanguage}
</a>
);
}
export default PrimaryNav;

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 do I pass props to nested route as I am having undefined in this.props.match

I have successfully implemented some nested routes to show different navbar depending on the component being rendered, but I am having a problem passing props through them.
Here is an example code of my routes.
<Route exact path="/admin/dashboard/update/:slug" render={() => <Dashboard><UpdateProperty /></Dashboard>} />
<Route exact path="/property/:slug" render={() => <Layout><SingleProperty /></Layout> } />
and here is where I pass the props through Link component
<Link to={`/admin/dashboard/update/${property.slug}`} >
<Link to={ `/property/${ slug }` } className="btn-primaryCustom room-link">view Details</Link>
I tried to destructure the slug like this.
const { slug } = this.props.match.params
but it gives me an error. TypeError: Cannot read property 'params' of undefined
The challenge is that I can see the slug in my browser menu but when I try to get it using this.props.match.params it throughs an error. I then logged this.props.match to the console and got undefined.
The code for the dashboard component is below:
// components
import DashboardNav from '../components/DashboardNav'
const Dashboard = ({ children }) => {
return (
<section className="">
<div className="row">
<div id="main" className="col-sm-12 d-flex">
<aside id="sidebar" className="dashboard col-md-2 bg-secondary">
<ul className="nav flex-column justify-content-center align-items-center">
<li className="nav-item py-md-4 px-md-3">
<Link className="nav-link active text-white" to="#">Logo</Link>
</li>
<li className="nav-item p-md-3">
<Link className="nav-link active text-white" to="#">Dashboard</Link>
</li>
<li className="nav-item p-md-3">
<Link className="nav-link text-white" to="#">All Properties</Link>
</li>
<li className="nav-item p-md-3">
<Link className="nav-link text-white" to="#">New Properties</Link>
</li>
<li className="nav-item p-md-3">
<Link className="nav-link text-white" to="#">Messages</Link>
</li>
<li className="nav-item p-md-3">
<Link className="nav-link text-white" to="#">About</Link>
</li>
<li className="nav-item p-md-3">
<Link className="nav-link text-white" to="#">Contact</Link>
</li>
<li className="nav-item p-md-3">
<Link className="nav-link text-white" to="#">Blog</Link>
</li>
<li className="nav-item p-md-3">
<Link className="nav-link text-white" to="#">Logout</Link>
</li>
</ul>
</aside>
<article id="dashboard" className="col-sm-12 col-md-10">
<header id="menu" className="dashboard d-flex flex-column">
<DashboardNav />
</header>
<main className="py-md-3">
{/* { loading && <Loading /> } */}
{ children }
</main>
</article>
</div>
</div>
</section>
)
}
And the Layout component is below:
import React from 'react';
// components
import Navbar from './Navbar'
const Layout = ({ children }) => {
return (
<>
<Navbar />
{ children }
</>
);
}
export default Layout;
I do know there is a way to implement this but I can't seem to get the correct method yet.
I think you need to use the withRouter HOC to access match inside your component
import { withRouter } from 'react-router-dom';
and then wrap your component export as
export default withRouter(Component)
Then you will get access to match prop.
Hope it helps.
I have been able to solve this by setting up my routes as follows:
<Route exact path="/admin/dashboard/update/:slug" render={(props) => <Dashboard><UpdateProperty { ...props } /></Dashboard>} />
<Route exact path="/property/:slug" render={(props) => <Layout><SingleProperty { ...props } /></Layout> } />
And this works.

Resources