I am trying to add 'active' class name to clicked navbar item dynamically and remove the 'active' class name from class respectively. I am using bootstrap so 'active' class name change the color of the li item.
class NavBar extends React.Component {
render() {
return (
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Blog - App</a>
</div>
<ul class="nav navbar-nav">
<li class="active">Home</li>
<li>Chat</li>
<li>About</li>
</ul>
</div>
</nav>
);
};
};
export default NavBar
I am new with React, do i need to handle onClick with a function? I will appreciate any idea or code suggestions.
In react you can do it like this:
By passing in a prop which determines the toggle of className.
const NavBar = props => {
return (
<nav className="navbar navbar-inverse">
<div class="container-fluid">
<div className="navbar-header">
<Link className="navbar-brand">Blog - App</Link>
</div>
<ul className="nav navbar-nav">
<li className={props.active ? 'active' : ''}><Link to="/main">Home</Link></li>
<li><Link to="/chat">Chat</Link></li>
<li><Link to="/about">About</Link></li>
</ul>
</div>
</nav>
);
};
export default NavBar
By State
But then in this case wouldn't be appropriate because nothing is going to click it.
import {useState} from 'react';
const NavBar = () => {
const [active, setActive] = useState('');
clickToChange () {
setActive(true);
}
render() {
return (
<nav className="navbar navbar-inverse">
<div class="container-fluid">
<div className="navbar-header">
<Link className="navbar-brand">Blog - App</Link>
</div>
<ul className="nav navbar-nav">
<li className={state.active ? 'active' : ''}><Link to="/main">Home</Link></li>
<li><Link to="/chat">Chat</Link></li>
<li><Link to="/about">About</Link></li>
</ul>
</div>
</nav>
);
};
};
export default NavBar
In your particular use case I'd probably suggest instead detecting the route
See example here:
React Router v4 - How to get current route?
yes, you could use onClick handler, but then again you will have to rehydrate it from the window.location;
class NavBar extends React.Component {
render() {
state = { active : null }
componentDidMount(){
/** you might as well check if location.pathname includes what you are looking
for before just setting it to state, assuming that there wont be anything
extra; skipping that for simplicity*/
this.setState(window.location.pathname);
}
handleClick = (activeLink) => {
this.setState(activeLink);
}
return (
<nav className="navbar navbar-inverse">
<div className="container-fluid">
<div className="navbar-header">
<a className="navbar-brand" href="#">Blog - App</a>
</div>
<ul className="nav navbar-nav">
<li onClick={()=>this.handleClick('/main')} className={`{this.state.active==='/main'? 'active':''}`}>Home</li>
</ul>
</div>
</nav>
);
};
};
export default NavBar
A more graceful implementation would be using a client side routing library like react-router which gives you Link components like NavLink which attaches active classnames automatically.
Related
The code below works completely fine and results in the image below.
import React from "react";
import "./App.css";
import { useState } from "react";
function App(){
return(
<body>
<div className="nav_bar">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"></link>
<ul className="top">
<div className="circle circle1">
<li className="material-icons noselect">
drag_handle
</li>
</div>
<div className="circle circle2">
<li className="material-icons noselect">
home
</li>
</div>
<div className="circle circle3">
<li className="material-icons noselect">
person_outline
</li>
</div>
</ul>
<nav>
<ul className="bottom">
<li className="material-icons noselect" id="feed-bottom">
drag_handle
</li>
<li className="material-icons noselect" id="home-bottom">
home
</li>
<li className="material-icons noselect" id="profile-bottom">
person_outline
</li>
</ul>
</nav>
</div>
</body>
);
}
export default App;
Result
Adding useState to get and set the current state causes the navbar to disappear and show a completely white screen. Specifically I am using useState to change the icon shown in the nav bar to text and to set the currernt state to the icon that is clicked. Code Below
import React from "react";
import "./App.css";
import { useState } from "react";
function App(){
const[selected, setselected] = useState('home');
if(selected === 'feed'){
const feed = document.getElementById('feed-bottom');
feed.innerHTML = 'FEED';
} else if (selected === 'profile') {
const profile = document.getElementById('profile-bottom');
profile.innerHTML = 'PROFILE';
}else{
const home = document.getElementById('home-bottom');
home.innerHTML = 'HOME';
}
return(
<body>
<div className="nav_bar">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"></link>
<ul className="top">
<div className="circle circle1">
<li className="material-icons noselect">
drag_handle
</li>
</div>
<div className="circle circle2">
<li className="material-icons noselect">
home
</li>
</div>
<div className="circle circle3">
<li className="material-icons noselect">
person_outline
</li>
</div>
</ul>
<nav>
<ul className="bottom">
<li className="material-icons noselect" id="feed-bottom" onClick={setselected('profile')}>
drag_handle
</li>
<li className="material-icons noselect" id="home-bottom" onClick={setselected('home')}>
home
</li>
<li className="material-icons noselect" id="profile-bottom" onClick={setselected('profile')}>
person_outline
</li>
</ul>
</nav>
</div>
</body>
);
}
export default App;
I've looked up many post that refernece similar issues but couldn't find one that pretained to mine. I would grealty appreciate some assitance.
This line
home.innerHTML = 'HOME';
will cause an error on mount, because on mount, the React elements returned from App haven't been returned yet - the container is still empty; the #feed-bottom element doesn't exist yet.
While you could fix it by only assigning if the element actually exists, it would be far better to do it the React way and put the values conditionally into the JSX. Don't use vanilla DOM methods in React unless you absolutely have to.
Another problem is that your listeners - eg onClick={setselected('home')} - run when computed (immediately), because you're invoking the setselected function instead of passing a function as a prop to onClick.
You also probably meant to pass feed in the feed-bottom element (instead of profile).
To implement your logic in the React way, you need something like:
<li className="material-icons noselect" id="feed-bottom" onClick={() => setselected('feed')}>
{ selected === 'feed' ? 'FEED' : 'drag_handle' }
</li>
<li className="material-icons noselect" id="home-bottom" onClick={() => setselected('home')}>
{ selected === 'home' ? 'HOME' : 'home' }
home
</li>
<li className="material-icons noselect" id="profile-bottom" onClick={() => setselected('profile')}>
{ selected === 'profile' ? 'PROFILE' : 'person_outline' }
person_outline
</li>
and remove all of the if(selected === 'feed'){ and the like code from the top.
I have a simple navbar and when a user hovers over a <li> tag it must turn red. When the user removes their cursor it must turn grey. It works but not properly. Inside <li> tags I have <Link> provided by react-router-dom and when I target <li> tag it works properly but when I target <Link> it does not work on parent tag (<li>).
Here is my code:
Navbar.js:
return(
<nav className={this.props.navClass}>
<ul>
<li
className="main"
style={{transitionDuration: "0.9s"}}
onMouseEnter={this.props.mouseEnter}
onMouseLeave={this.props.mouseLeave}
>
<Link to="/">მთავარი</Link>
</li>
<li
className="aboutUs"
>
<Link
to="/about-us"
onMouseEnter={this.props.mouseEnter}
onMouseLeave={this.props.mouseLeave}
>ჩვენს შესახებ</Link></li>
<li
className="contactUs"
onMouseEnter={this.props.mouseEnter}
onMouseLeave={this.props.mouseLeave}
>
<Link to="/contact">დაგვეკონტაქტე</Link>
</li>
</ul>
</nav>
)
Main.js:
hover(e) {
e.preventDefault();
e.target.style.backgroundColor = 'red'
}
mouseLeave(e) {
e.target.style.backgroundColor = 'grey'
}
render() {
return(
<div className="wrapper">
<div className="navBar">
<Navbar
navClass="navbar"
mouseEnter={this.hover.bind(this)}
mouseLeave={this.mouseLeave.bind(this)}
/>
</div>
</div>
)
}
How can I fix it?
By the way, I will be glad if you tell me if I am breaking UI in different components correctly.
Thank you!
you could add link{pointer-events:none} to your css.
First, in the Navbar component you need to wrap up your Links inside Router:
import { BrowserRouter as Router, Link } from "react-router-dom";
return (
<nav className={this.props.navClass}>
<Router>
<ul>
<li className="main" style={{transitionDuration: "0.9s"}} onMouseEnter={this.props.mouseEnter} onMouseLeave={this.props.mouseLeave}>
<Link to="/">მთავარი</Link>
</li>
<li className="aboutUs">
<Link to="/about-us" onMouseEnter={this.props.mouseEnter} onMouseLeave={this.props.mouseLeave}>ჩვენს შესახებ</Link>
</li>
<li className="contactUs" onMouseEnter={this.props.mouseEnter} onMouseLeave={this.props.mouseLeave}>
<Link to="/contact">დაგვეკონტაქტე</Link>
</li>
</ul>
</Router>
</nav>
);
The above code works fine, in the second <li className="aboutUs"></li> the reason that only <Link /> component is highlighted and not its parent (li) is that Link component equivalents to <a></a> and its display is inline.
If you add the following css, the parent li is also highlighted.
a {display: block;}
I am trying to When user clicks on list set a state
I have listing in li tag in a loop when user click one of li tag i want to update some state but react throws error.
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested
Here my main piece of code:
class Header extends React.Component{
constructor(props){
super(props);
this.showCatDetail=this.showCatDetail.bind(this);
this.state={
category:[],
clk_category:[],
detail:false
}
}
componentDidMount() {
fetch('http://127.0.0.1:8000/portfolio/create_category/')
.then(response=>response.json())
.then(categoryJson => this.setState({category: categoryJson},()=>{
this.sortCategory()
}))
}
showCatDetail=(e)=>{
e.preventDefault();
this.setState({detail:true,clk_category:JSON.parse(e.currentTarget.getAttribute('data-item'))},()=>{
console.log(this.state.clk_category)
});
};
sortCategory = ()=>{
let sortArray=this.state.category;
let swap;
for (let i=0;i<sortArray.length;i++)
{
for (let j=0;j<sortArray.length;j++){
if(sortArray[i].category_rank>sortArray[j].category_rank){
swap=sortArray[i];
sortArray[i]= sortArray[j];
sortArray[j]=swap;
}
}
}
this.setState({category:sortArray})
};
render(){
let hreflink=null;
let redirect=null;
if (this.state.detail){
redirect=<Redirect to={`/category_project/${this.state.clk_category.id}`}/>
}
return(
<div>
{redirect}
<header id="header">
<div id="trueHeader">
<div className="wrapper">
<div className="container">
<div className="logo">
<a href={hreflink} id="logo">
</a>
</div>
<div className="menu_main">
<div className="navbar yamm navbar-default">
<div className="container">
<div className="navbar-header">
<div className="visibledevice">
<ul className="nav navbar-nav">
<li><a href={hreflink} className="active">
<i className="fa fa-home">
</i> Home</a></li>
</ul>
</div>
</div>
<div className="navbar-collapse collapse pull-right">
<ul className="nav navbar-nav">
<li><a href={hreflink} className="active">
<i className="fa fa-home">
</i> Contact Us</a></li>
{this.state.category.map(cat=>{
return(
<li data-item={JSON.stringify(cat)} onClick={(e)=>this.showCatDetail(e)}><a href={hreflink} >
<i className="fa fa-home">
</i>{cat.category_name}</a></li>
)
})}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
</div>
)
}
}
I can't figure out what the problem is...
onClick={(e)=>{this.showCatDetail(e)}}
Try this in onclick
check this image> Hi all I'm trying to use optionsBar & optionsPie as dropdown options in my header-list item, just like how I'm using other links for home and aboutUs
Hi all I'm trying to use optionsBar & optionsPie as dropdown options in my header-list item, just like how I'm using other links for home and aboutUs
import React, {Component} from 'react'
import { Link } from 'react-router-dom'
import { Dropdown, Menu, Icon} from `semantic-ui-react`;
const optionsBar = [
{as: Link, content: 'Rank ', to: '/barT', key: 'Rank'},
{as: Link, content: 'Category', to: '/barK', key: 'Category'},
]
const optionsPie = [
{as: Link, content: 'Rank ', to: '/pieT', key: 'Rank'},
{as: Link, content: 'Category', to: '/pieK', key: 'Category'},
]
class Header extends Component{
render(){
return (
<header>
<nav className="navbar navbar-inverse">
<div className="container-fluid">
<div className="navbar-header">
<a className="navbar-brand" href="/">Relation document </a>
</div>
<ul className="nav navbar-nav ">
<li><Link to='/'>Home</Link></li>
<li><Link to='/page1'>ABout Us</Link></li>
<li><Link to='/page2'>Info</Link></li>
<li class="nav-item dropdown">
<a class="nav dropdown">
<Dropdown header=`Select Rank or Category` options={optionsBar} defaultValue={optionsBar[0].value} text='Bar' />
</a>
</li>
<li class="nav-item dropdown">
<a class="nav dropdown">
<Dropdown header='Select Rank or Category' options={optionsPie} defaultValue={optionsPie[0].value} text='Pie' />
</a>
</li>
</ul>
</div>
</nav>
</header>
)
}
}
export default Header
error: Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>
You are getting this error because you have two <a> tags nested in each other, e.g.
<a><a>...</a></a>
I believe it is happening here:
<a class="nav dropdown">
<Dropdown options={optionsBar} .../>
</a>
The Dropdown items are rendered as Link components (see optionsBar), and because Link ultimately becomes an <a> tag, you get nested <a> tags.
I am pretty new to developing in React and Javascript. I am bulding an application with a side menu. I wanted to display different components based on the selection in side menu. Can someone guide me how to do this. I am attaching my menu component and index code here.
class AppIndex extends Component {
constructor(props) {
super(props);
}
render () {
return (
<Navbar />
<div className="row">
<div className="col-md-2">
<MenuComponent/>
</div>
<div className="col-md-10">
// I need to add the components here based on selected item in menu
</div>
</div>
);
}
}
class MenuComponent extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ul className=" nav nav-pills mr-auto flex-column">
<li className="nav-item">
Overview
</li>
<li className="nav-item">
Component1
</li>
<li className="nav-item">
Component2
</li>
<li className="nav-item">
Component3
</li>
<li className="nav-item">
Component4
</li>
<li className="nav-item">
Component5
</li>
</ul>
);
}
}
im sorry i didnt see your top level component.
Now from my experience, i wanna give you a little advice, don't let any child component render another component. try to avoid that as much as possible.
Here's what i would do.
This is the Top Level Component
class AppIndex extends Component {
constructor(props) {
super(props);
this.state = { component: '' };
this.selectComponent = this.selectComponent.bind(this); // dont forget to bind
}
selectComponent(event){ // this will take the name of the button thats beeing clicked and sets name of button to state
event.preventDefault();
this.setState({component: event.target.name});
}
render () {
let toRender = null;
switch(this.state.component)
{
case "component 1":
toRender = <Component1/>
case "component 2":
toRender = <Component2/>
case "component 3":
toRender = <Component3/>
}
return (
<Navbar />
<div className="row">
<div className="col-md-2">
<MenuComponent onClick = {this.selectComponent}/>
</div>
<div className="col-md-10">
{toRender} //here goes the component
</div>
</div>
);
}
}
this is the menu
const MenuComponent = ({onClick}) => { // you dont need a class component for this
return (
<ul className=" nav nav-pills mr-auto flex-column">
<li className="nav-item">Overview</li>
<li className="nav-item"> <button onClick = {onClick} name = "component 1">Component1</button></li>
<li className="nav-item"> <button onClick = {onClick} name = "component 2">Component2</button></li>
<li className="nav-item"> <button onClick = {onClick} name = "component 3">Component3</button></li>
</ul>
);
}
thats it.
easy.. You already have the name of the button in the top level component's state right?
send it down as props to the MenuComponent and on every button write something like,
here im assuming the name of the props the MenuComponent get is name
<li className="nav-item"> <button className = {this.props.name === "component 1"?"Active":""} onClick = {onClick} name = "component 1">Component1</button></li>