My logo also get underlined while using activeClassName attribute in react.js - javascript

I am using activeClassName="active" to style the nav menu items, so active page name should be underlined. The only problem is when the user is on homepage the logo also get underlined/styled while I want the home item in the nav menu to be underlined or styled.
Every page name in the nav menu gets styled when I am on the active page, the only problem is when I am on homepage the logo get styled while I only want the 'home' item in the nav menu to be styled.
<nav className="navbar navbar-expand-lg bg-body-tertiary">
<div className="container-fluid">
<NavLink className="navbar-brand" to="/">Nomdev</NavLink>
<button
className="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav ms-auto mb-2 mb-lg-0">
<li className="nav-item">
<NavLink
activeClassName='active'
className="nav-link"
aria-current="page"
to="/"
>
Home
</NavLink>
</li>
<li className="nav-item">
<NavLink
activeClassName='active'
className="nav-link"
to="/service"
>
Service
</NavLink>
</li>
<li className="nav-item">
<NavLink
activeClassName='active'
className="nav-link"
to="/about"
>
About
</NavLink>
</li>
<li className="nav-item">
<NavLink
activeClassName='active'
className="nav-link"
to="/contact"
>
Contact
</NavLink>
</li>
</ul>
</div>
</div>
</nav>

Since activeClassName is a react-router-dom#5 NavLink component prop you'll want to use the exact prop to indicate you want the link to exactly match the current URL path.
exact
When true, the active class/style will only be applied if the location
is matched exactly.
<NavLink className="navbar-brand" to="/" exact>Nomdev</NavLink>
...
<NavLink
activeClassName='active'
className="nav-link"
aria-current="page"
to="/"
exact
>
Home
</NavLink>
If you happen to be using react-router-dom#6 and still have the activeClassName there for some reason, then the prop you would use is the end prop. You'd want to convert to using the RRDv6 props to set any active classnames.
RRDv6 NavLink
declare function NavLink(
props: NavLinkProps
): React.ReactElement;
interface NavLinkProps
extends Omit<
LinkProps,
"className" | "style" | "children"
> {
caseSensitive?: boolean;
children?:
| React.ReactNode
| ((props: { isActive: boolean }) => React.ReactNode);
className?:
| string
| ((props: {
isActive: boolean;
}) => string | undefined);
end?: boolean;
style?:
| React.CSSProperties
| ((props: {
isActive: boolean;
}) => React.CSSProperties);
}
...
If the end prop is used, it will ensure this component isn't matched
as "active" when its descendant paths are matched. For example, to
render a link that is only active at the website root and not any
other URLs, you can use:
<NavLink to="/" end>
Home
</NavLink>
<NavLink className="navbar-brand" to="/" end>Nomdev</NavLink>
...
<NavLink
className={({ isActive }) =>
["nav-link", isActive ? "active" : null]
.filter(Boolean)
.join(" ")
}
aria-current="page"
to="/"
end
>
Home
</NavLink>

Related

Uncaught TypeError: Cannot read properties of undefined (reading 'length')

I am creating an eCommerce website and getting the error in the title.
This is my Navbar element, where I'm using state.length:
import React from "react";
import { useSelector } from "react-redux";
import { NavLink } from "react-router-dom";
const Navbar = () => {
const state = useSelector((state) => state.handleCart);
return (
<div>
<nav className="navbar navbar-expand-lg bg-white py-3 shadow-sm">
<div className="container">
<NavLink className="navbar-brand fw-bold fs-5" to="/">
Some Generic Shop
</NavLink>
<button
className="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav mx-auto mb-2 mb-lg-0">
<li className="nav-item">
<NavLink className="nav-link active" aria-current="page" to={`/`}>
Home
</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to={`/products`}>
Products
</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to={`/about`}>
About
</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to={`/contact`}>
Contact us!
</NavLink>
</li>
</ul>
<div className="buttons my-3 mx-1">
<NavLink to="/login" className="btn btn-outline-dark">
<i className="fa fa-sign-in me-1"></i> Login
</NavLink>
</div>
<div className="buttons my-3 mx-1">
<NavLink to="/register" className="btn btn-outline-dark">
<i className="fa fa-user-plus me-1"></i> Sign up
</NavLink>
</div>
<div className="buttons my-3 mx-1">
<NavLink to="/cart" className="btn btn-outline-dark">
<i className="fa fa-shopping-cart me-1"></i> Cart({state.length})
</NavLink>
</div>
</div>
</div>
</nav>
</div>
);
};
export default Navbar;
This is my handleCart.js
const cart=[];
const handleCart = (state = cart, action) => {
const product = action.payload;
switch(action.type) {
case "ADDITEM":
//check if product exists
const exist_1 = state.find((x) => x.id === product.id);
if(exist_1){
//increase quantity
return state.map((x)=>
x.id === product.id ? {...x, qty: x.qty + 1}: x
);
} else {
const product = action.payload;
return[
...state,
{
...product,
qty: 1,
}
]
}
break;
case "DELETEITEM":
const exist_2 = state.find((x) => x.id === product.id);
if(exist_2.qty === 1){
return state.filter((x)=> x.id !==exist_2.id);
}else{
return state.map((x)=>
x.id === product.id ? {...x, qty: x.qty-1} : x
);
}
break;
default:
return state;
break;
}
}
and the index.js
import handleCart from "./handleCart";
import { combineReducers } from "redux";
const rootReducers = combineReducers({
handleCart,
})
export default rootReducers;
I'm completely new to React, so let me know what else you need me to show. I needed the Cart() in the navbar to show the number of items added. But it just returns this error. It works whenever I remove "state.length".
When I added state?.length, some of my app started to render, but the cart doesn't work still, and every time I click on add to cart, this error shows up:
Store does not have a valid reducer. Make sure the argument passed to combineReducers is an object whose values are reducers.
Not sure why the formatting error, I hope you guys get it!
It means when you call {{state.length}},it didn't exsit yet.
To fix this, you can set code to this:
<NavLink to="/cart" className="btn btn-outline-dark">
<i className="fa fa-shopping-cart me-1"></i>
{state.length?Cart({state.length}):""}
</NavLink>
Means:
When state.length is defined, then call Cart({state.length}) or do nothing.

Having An Issue With Fontawesome icons returning as boxes

So, Im trying to set up a hamburger menu setup where the icons appears when I shrink my browser down to a mobile size, and when the hamburger icon is clicked, its replaced with an X icon until I click it again to close the mobile menu. My issue is that even with the CDN appropriately placed in my index.html file, my icons are appearing as boxes. I've tried importing the library to my navbar page in a variety of different ways, but haven't been able to find out what exactly Ive done wrong. I did manage to get the faMonsterTruck icon to load, but how I got this icon to work is not working in my click event. My code for my navbar.js page looks as such:
import React, { useState, useEffect } from "react";
import "./navbar.css";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { Link } from "react-router-dom";
import { faTruckMonster } from "#fortawesome/free-solid-svg-icons";
function Navbar() {
const [click, setClick] = useState(false);
const [button, setButton] = useState(true);
const handleClick = () => setClick(!click);
const closeMobileMenu = () => setClick(false);
const showButton = () => {
if (window.innerWidth <= 960) {
setButton(false);
} else {
setButton(true);
}
};
useEffect(() => {
showButton();
}, []);
window.addEventListener("resize", showButton);
return (
<div>
<nav className="navbar">
<div className="navbar-container">
<Link to="/" className="navbar-logo" onClick={closeMobileMenu}>
EPC
<FontAwesomeIcon icon={faTruckMonster} />
</Link>
<div className="menu-icon" onClick={handleClick}>
<i className={click ? "fas fa-times" : "fas fa-bars"} />
</div>
<ul className={click ? "nav-menu active" : "nav-menu"}>
<li className="nav-item">
<Link to="/" className="nav-links" onClick={closeMobileMenu}>
Home
</Link>
</li>
<li>
<Link to="/zero" className="nav-links" onClick={closeMobileMenu}>
Year 0
</Link>
</li>
<li className="nav-item">
<Link to="/one" className="nav-links" onClick={closeMobileMenu}>
Year 1
</Link>
</li>
<li className="nav-item">
<Link to="/two" className="nav-links" onClick={closeMobileMenu}>
Year 2
</Link>
</li>
<li className="nav-item">
<Link to="/three" className="nav-links" onClick={closeMobileMenu}>
Year 3
</Link>
</li>
<li className="nav-item">
<Link to="/four" className="nav-links" onClick={closeMobileMenu}>
Year 4
</Link>
</li>
</ul>
</div>
</nav>
</div>
);
}
export default Navbar;
In case it's difficult to locate where I need help exactly, the click event code I referenced is this snippet here:
<div className="menu-icon" onClick={handleClick}>
<i className={click ? "fas fa-times" : "fas fa-bars"} />
</div>
<ul className={click ? "nav-menu active" : "nav-menu"}>
<li className="nav-item">
I know that I have some useless code in there for button calls. Im cleaning up the page as I go, as my plans for how I want my page to appear have changed a couple times.

check if JSON has child elements multiple times within a return

I am trying to check the length (or if it even exists ) of JSON child elements before I loop through them.
my example has a note:
{const itHasChildren = item.child_items.length;}
the error I get with above is
src/Components/HeaderComponent/header.js
Line 60:29: 'childItem' is not defined no-undef
Search for the keywords to learn more about each error.
return (
<nav >
<ul className="navbar-nav">
{menus &&
menus.map((item) => (
<li className="nav-item active" key={item.ID}>
<Link >{item.title} </Link>
// I NEED TO CHECK THE LENGTH OR IF child_items EXISTS
// HERE SO I CAN DECIDE WHETHER TO DISPLAY THIS DIV OR NOT
{item.child_items.map((childItem).length)}
<div className="dropdown-menu" aria-labelledby="navbarDropdownMenuLink" >
{item.child_items &&
item.child_items.map((childItem) => (
<Link >{childItem.title} </Link>
))}
</div>
</li>
))}
</ul>
</nav>
);
I've cleaned up your code a bit so it should work. Just the first element inside the map needs the key and according to your data it could be the index position in the array
return (
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarNavDropdown"
aria-controls="navbarNavDropdown"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavDropdown">
<ul className="navbar-nav">
{(menus || []).map((item, ix) => (
<li key={ix} className="nav-item active">
<Link
className="nav-link"
to={{
pathname: item.slug,
state: {
pageId: item.slug
}
}}
>
{item.title}
</Link>
{(item.child_items || []).map((childItem, ix) => (
<div key={ix} className="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<Link
className="dropdown-item"
to={{
pathname: childItem.slug,
state: {
pageId: childItem.slug
}
}}
>
{childItem.title}
</Link>
</div>
))}
</li>
))}
</ul>
</div>
</nav>
);
here is the syntax and condition I was looking for
<li
className={
item.child_items
? "nav-item dropdown"
: "nav-item "
}

Change header background color on other pages in ReactJS

I have following react code.
My code
What I would like is to when I click on "home" menu background should change on red in other cases on blue.
I write
style={{background: window.location.pathname == "/" ? "red" : "blue"}}
but it working only when I am refreshing browser.
Consider using the useLocation hook. useLocation allows you to get the current path by doing:
let location = useLocation();
console.log(location.pathname);
So your problem can be solved by changing your Navigation.js to this:
import React from "react";
import { NavLink, useLocation } from "react-router-dom";
const Navigation = () => (
<nav
style={{
background: useLocation().pathname !== "/" ? "red" : "blue"
}}
>
<ul>
<li>
<NavLink exact activeClassName="active" to="/">
Home
</NavLink>
</li>
<li>
<NavLink exact activeClassName="active" to="/about">
About
</NavLink>
</li>
<li>
<NavLink exact activeClassName="active" to="/contact">
Contact
</NavLink>
</li>
</ul>
</nav>
);
export default Navigation;
You can see the changes in action here.
An option would be to declare new styles and assign them using a state variable
in the .css file
.blue {
background: blue;
}
.red {
background: red;
}
and then use as follows
import React, {useState} from "react";
import { NavLink } from "react-router-dom";
const Navigation = (props) => {
const [sitestyle, setStyle] = useState("blue");
return(
<nav className={sitestyle}>
<ul>
<li>
<NavLink exact activeClassName="active" to="/">
Home
</NavLink>
</li>
<li>
<NavLink exact activeClassName="active" to="/about" onClick={() => {setStyle("red")}}>
About
</NavLink>
</li>
<li>
<NavLink exact activeClassName="active" to="/contact">
Contact
</NavLink>
</li>
</ul>
</nav>
)
};
export default Navigation;

How can I change the className of an element on click? (hamburger menu)

I'm trying to make a hamburger menu, on click I want the 'mobile view hamburger' to drop down (go from display: flex to display: initial). Seems that I can't get the js to work..
I'm totally new to JavaScript and React, could someone explain what's missing?
The html which is returned and exported from the function Nav and rendered in App.js:
<div class="Navbar__Link Navbar__Link-brand">
<NavLink to="/" exact>
<img className="logo" src="https://i.imgur.com/KnEvuRJ.png"></img>
</NavLink>
</div>
<div class="Navbar__Link Navbar__Link-toggle">
<i class="fa fa-bars"></i>
</div>
<nav class="Navbar__Items">
<div class="Navbar__Link">
<NavLink className="nav-link" to="/" exact activeClassName="active">
Home
</NavLink>
</div>
<div class="Navbar__Link">
<NavLink className="nav-link" to="/about" activeClassName="active">
About
</NavLink>
</div>
<div class="Navbar__Link">
<NavLink className="nav-link" to="/chars" activeClassName="active">
Characters
</NavLink>
</div>
<div class="Navbar__Link">
<NavLink className="nav-link" to="/login" activeClassName="active">
Login
</NavLink>
</div>
</nav>
</div>
The js code to toggle:
function classToggle() {
const navs = document.querySelectorAll('.Navbar__Items')
navs.forEach(nav => nav.classList.toggle('Navbar__ToggleShow'));
}
document.querySelector('.Navbar__Link-toggle')
.addEventListener('click', classToggle);
The css: ( inside #media..)
.Navbar__Link-toggle {
align-self: flex-end;
display: initial;
position: absolute;
cursor: pointer;
}
TypeError: Cannot read property 'addEventListener' of null
This isn't how React works, there is absolutely no need to use vanilla js here. What about binding the class toggle behavior with a state's property ?
class Component extends React.Component{
state = {
isButtonToggled: false
}
handleClick = () => this.setState({isButtonToggled : !this.state.isButtonToggled})
render(){
const { isButtonToggled } = this.state
const buttonStyle = classnames({
['button-root'] : true,
['button-toggled'] : isButtonToggled
})
return(
<button onClick={this.handleClick} className={buttonStyle}>Click</button>
)
}
}

Categories