I wanted to add an 'active' class to a menu element, written in ReactJS. I tried doing it with the conventional JS method, but it failed. A click on any <li> tag, should result is removal of the 'active' class from all the <li>, and retain/ add it only to the one list tag in which the click was triggered.
Note: I know it may seem very naive on my part, but I'm just starting with ReactJS. Please ignore the stupidity.
import React, { Component } from 'react';
class Sidebar extends Component{
render(){
return(
<div className="sidebarContainer p-2">
<div className="mainMenu">
<ul className="levelOne pl-0">
<li className="mb-3 pl-2 menuTitle active" id="MenuTitle1">
...
</li>
<li className="mb-3 pl-2 menuTitle" id="MenuTitle2" onClick={this.clickMenu.bind(this,'MenuTitle2')}>
...
</li>
<li className="mb-3 pl-2 menuTitle" id="MenuTitle3" onClick={this.clickMenu.bind(this,'MenuTitle3')}>
...
</li>
</ul>
</div>
</div>
);
}
clickMenu(id){
// Add class 'active' on the clicked <li>, and remove from all other <li>
}
}
export default Sidebar;
I saw a similar question here, but that couldn't help me.
Idea is, store the id of clicked item in state variable and put the check with className. If item's id is same as state value then only assign the className active.
Write it like this:
class Sidebar extends Component{
constructor() {
super()
this.state = {
activeItem: 'MenuTitle1'
}
}
clickMenu(id){
// Add class 'active' on the clicked <li>, and remove from all other <li>
this.setState({
activeItem: id,
})
}
getClassName(id) {
if(id === this.state.activeItem) return 'mb-3 pl-2 menuTitle active'
return 'mb-3 pl-2 menuTitle'
}
render(){
return(
<div className="sidebarContainer p-2">
<div className="mainMenu">
<ul className="levelOne pl-0">
<li
id="MenuTitle1"
className={this.getClassName('MenuTitle1')}
onClick={this.clickMenu.bind(this,'MenuTitle1')}>
...
</li>
<li
id="MenuTitle2"
className={this.getClassName('MenuTitle2')}
onClick={this.clickMenu.bind(this,'MenuTitle2')}>
...
</li>
<li
id="MenuTitle3"
className={this.getClassName('MenuTitle3')}
onClick={this.clickMenu.bind(this,'MenuTitle3')}>
...
</li>
</ul>
</div>
</div>
);
}
}
You can maintain the state for clicked menu item:
clickMenu(id){
this.setState({activeMenu: id})
}
Then, define className like this:
className={
this.state.activeMenu == id {/* eg. "MenuTitle1" */}
? 'mb-3 pl-2 menuTitle active'
: 'mb-3 pl-2 menuTitle'
}
Like Bhojendra suggested store datas linked to your display inside your state then when you want to update the display of your component use the method setState, this will trigger render again (react style).
import React, { Component } from 'react';
import ReactDOM from "react-dom";
class Sidebar extends Component {
constructor() {
super();
this.state = {
activeMenuId: "MenuTitle1"
};
}
render() {
return (
<div className="sidebarContainer p-2">
<div className="mainMenu">
<ul className="levelOne pl-0">
<li className={`mb-3 pl-2 menuTitle ${this.state.activeMenuId === "MenuTitle1" ? "active" : ""}`} id="MenuTitle1" onClick={this.clickMenu.bind(this, 'MenuTitle1')}>
1
</li>
<li className={`mb-3 pl-2 menuTitle ${this.state.activeMenuId === "MenuTitle2" ? "active" : ""}`} id="MenuTitle2" onClick={this.clickMenu.bind(this, 'MenuTitle2')}>
2
</li>
<li className={`mb-3 pl-2 menuTitle ${this.state.activeMenuId === "MenuTitle3" ? "active" : ""}`} id="MenuTitle3" onClick={this.clickMenu.bind(this, 'MenuTitle3')}>
3
</li>
</ul>
</div>
</div>
);
}
clickMenu(id) {
// Add class 'active' on the clicked <li>, and remove from all other <li>
this.setState({activeMenuId: id});
}
}
export default Sidebar;
ReactDOM.render(<Sidebar />, document.body);
Another way of just make using initialstate and setState.
import React, { Component } from "react";
class Sidebar extends Component {
constructor(props) {
super(props);
this.initialState = {
MenuTitle1: "active",
MenuTitle2: "",
MenuTitle3: ""
};
this.state = this.initialState;
}
render() {
return (
<div className="sidebarContainer p-2">
<div className="mainMenu">
<ul className="levelOne pl-0">
<li
className={`mb-3 pl-2 menuTitle ${this.state.MenuTitle1} `}
id="MenuTitle1"
onClick={this.clickMenu.bind(this, "MenuTitle1")}
>
one
</li>
<li
className={`mb-3 pl-2 menuTitle ${this.state.MenuTitle2}`}
id="MenuTitle2"
onClick={this.clickMenu.bind(this, "MenuTitle2")}
>
two
</li>
<li
className={`mb-3 pl-2 menuTitle ${this.state.MenuTitle3}`}
id="MenuTitle3"
onClick={this.clickMenu.bind(this, "MenuTitle3")}
>
three
</li>
</ul>
</div>
</div>
);
}
clickMenu(id) {
this.setState(this.initialState);
this.setState({
[id]: "active"
});
}
}
export default Sidebar;
Related
I have some code down and it works but my problem is that it changes all of the icons at the same time when i scroll over just one. I only want the icon that I hover over to change, so any help would be appreciated.
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {isHovered: false};
this.toggleHover = this.toggleHover.bind(this);
}
toggleHover() {
this.setState(prevState => ({isHovered: !prevState.isHovered}));
}
render() {
return (
<section className="info-section">
<div className="logo">
MATT
</div>
<div className="info-box">
<ul className="nav-links">
<li onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>
{this.state.isHovered
? <a className="home active" href="/">Home</a>
: <a className="home active" href="/"><FontAwesomeIcon icon={faHome} /></a>
}
</li>
<li onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>
{this.state.isHovered
? About
: <FontAwesomeIcon icon={faUser} />
}
</li>
Maybe you can try to use CSS.
<ul className="nav-links">
<li>
<a href="/">
<span>Home</span>
<FontAwesomeIcon icon={faHome} />
</a>
</li>
<li>
<a href="/about">
<span>Home</span>
<FontAwesomeIcon icon={faUser} />
</a>
</li>
...
a {
span {
display: none;
}
&:hover {
span {
display: block;
}
/* hide the icon base on their html tag or class */
i {
display: none;
}
}
}
If you really want to handle this through Javascript (which I'm not suggesting), you can try this.
class App extends Component {
state = {
hover: ""
};
handleMouseEnter = key => {
this.setState({ hover: key });
};
handleMouseLeave = () => {
this.setState({ hover: "" });
};
render() {
const { hover } = this.state;
return (
<ul>
<li
onMouseEnter={() => this.handleMouseEnter("home")}
onMouseLeave={this.handleMouseLeave}
>
<a href="/">
{hover === "home" ? <span>Hover Home</span> : <span>Home</span>}
</a>
</li>
<li
onMouseEnter={() => this.handleMouseEnter("about")}
onMouseLeave={this.handleMouseLeave}
>
<a href="/about">
{hover === "about" ? <span>Hover about</span> : <span>about</span>}
</a>
</li>
</ul>
);
}
}
I am having difficulty in changing state. I would like to change the state with images in an array that has a corresponding description to the images in the array. On click on the chapter should bring up the image and the description. Could you tell me what I am doing wrong here? Ignore chapters 3-6 as I haven't populated that code.
import React from "react";
import {Component} from "react";
import Layout from "../components/layout";
import styles from "./book1.module.css";
import image1 from "../images/rainbow.jpg"
import image2 from "../images/rainbow2.jpg"
class book extends Component {
constructor() {
super();
this.state= {
index : 0,
images : [image1, image2],
ChapterDescriptions: ["chapter1","chapter2"]
}
}
chapter1=()=>{
this.setState({
index: this.state.images.index[0]
})
}
chapter2=()=>{
this.setState({
index: this.state.chapterImages[1]
})
}
chapter3=()=>{
this.setState({
index: this.state.chapter3.image
})
}
chapter4=()=>{
this.setState({
index: this.state.chapter4.image
})
}
chapter5=()=>{
this.setState({
index: this.state.chapter5.image
})
}
chapter6=()=>{
this.setState({
index: this.state.chapter6.image
})
}
render(){
return (
<Layout>
<div className={styles.container}>
<div className={styles.chapters}>
<h1>Anti-Children</h1>
<p>
Learn how our leaders subvert our children’s future and what you can
do to brighten it
</p>
<ul>
<br/>
<br/>
<li className={styles.description} onClick={this.chapter1} > aaaaaaa</li>
<li className={styles.description} onClick={this.chapter2}> bbbbbbbbb</li>
<li className={styles.description} onClick={this.chapter3}> ccccccccc</li>
<li className={styles.description} onClick={this.chapter4}> ddddddddd</li>
<li className={styles.description} onClick={this.chapter5}> eeeeeeeee</li>
<li className={styles.description} onClick={this.chapter6}> fffffffff</li>
</ul>
</div>
<div className={styles.bookimage}>
<img href="#" className={styles.chapterImage} src={this.state.images.index}/>
<div className={styles.textArea} > {this.state.ChapterDescriptions.index}</div>
</div>
</div>
</Layout>
)
}
}
export default book
I've edited and added some parts of the code.
1. You can render some looped tag using map()
{this.state.ChapterDescriptions.map((item,index)=>{
return <li className={style.description} onClick={()=>{handleIndex(index)}>{item}</li>
})
}
2. You can combine your click event for update the state
handleIndex = (index) => {
this.setState({ index: index });
}
3. etc.
<div className={styles.bookimage}>
<img href="#" className={styles.chapterImage} src={this.state.images[this.state.index]}/>
<div className={styles.textArea} > {this.state.ChapterDescriptions[this.state.index]}</div>
</div>
Full code
import React from "react";
import {Component} from "react";
import Layout from "../components/layout";
import styles from "./book1.module.css";
import image1 from "../images/rainbow.jpg"
import image2 from "../images/rainbow2.jpg"
class book extends Component {
constructor() {
super();
this.state= {
index : 0,
images : [image1, image2],
ChapterDescriptions: ["chapter1","chapter2"]
}
}
handleIndex = (index) => {
this.setState({ index: index });
}
render(){
return (
<Layout>
<div className={styles.container}>
<div className={styles.chapters}>
<h1>Anti-Children</h1>
<p>
Learn how our leaders subvert our children’s future and what you can
do to brighten it
</p>
<ul>
<br/>
<br/>
{
this.state.ChapterDescriptions.map((item,index)=>{
return <li className={style.description} onClick={()=>{handleIndex(index)}>{item}</li>
})
}
</ul>
</div>
<div className={styles.bookimage}>
<img href="#" className={styles.chapterImage} src={this.state.images[this.state.index]}/>
<div className={styles.textArea} > {this.state.ChapterDescriptions[this.state.index]}</div>
</div>
</div>
</Layout>
)
}
}
export default book
Please check this code with live example demo. if you want like this you can iterate through map instead of writing hard coded.
let data = [{id:1,chapter: "chapter 1", image:'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRZlA55Pm9_SZbN90fmVOYgldndkgqSv6k88kQMzvDh36i_no7J&s'},
{id:2,chapter: "chapter 2", image:'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQLZZPW62TuM_Qgtu8lMZJ1U9to8BM2A4dEmC27ZyDpzWq9ZAxe&s'},
{id:3,chapter: "chapter 3", image:'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRFnKI9xni86qgmhlkHTN6utr__NX_vtgzpQSVBsnKM0Zzb92pG4g&s'},
{id:4,chapter: "chapter 4", image:'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Node.js_logo.svg/1200px-Node.js_logo.svg.png'},
{id:5,chapter: "chapter 5", image:'https://cdn2.iconfinder.com/data/icons/nodejs-1/512/nodejs-512.png'}]
class Book extends Component{
state={selected:''}
clickHandler=list=>{
this.setState({selected:list})
}
render(){
const {selected} =this.state;
return (
<div>
{data.map((d)=>
<p key={d.id} onClick={()=>this.clickHandler(d)}>
{d.chapter}
</p>
)}
<hr />
<h2>Please select an item from above list</h2>
{selected!==''&&<div>
<h3>{selected.chapter}</h3>
<img src={selected.image} alt="chapterimg"
style={{height:100,width:150}}/>
</div>}
</div>
)
}
}
check this for your reference Live demo
First, writing redundant <li> is not a good idea, you can change this by looping through a map function.
{
this.state.ChapterDescriptions.map((item,index)=>(
<li className={style.description} onClick={()=>this.setState({in
dex})}>
{item}
</li>)
}
and for showing the corresponding image
{
<div className={styles.bookimage}>
<img href="#" className={styles.chapterImage} src={this.state.images[this.state.index]}/>
<div className={styles.textArea} > {this.state.ChapterDescriptions[this.state.index]}</div>
</div>
}
Problem:
I am creating a React web application. In there I have created a side navbar like this.
import React, { PureComponent } from "react";
import imagine from "../../../assets/img/sidebar-2.jpg";
class Sidebar extends PureComponent {
constructor(props) {
super(props);
this.state = {
width: window.innerWidth,
activeTabClassName: "tab1"
};
}
// activeRoute(routeName) {
// return this.props.location.pathname.indexOf(routeName) > -1 ? "active" : "";
// }
updateDimensions() {
this.setState({ width: window.innerWidth });
}
componentDidMount() {
this.updateDimensions();
window.addEventListener("resize", this.updateDimensions.bind(this));
}
render() {
const sidebarBackground = {
backgroundImage: "url(" + imagine + ")"
};
return (
<div className="sidebar" data-image={imagine} id="sidebar">
<div className="sidebar-background" style={sidebarBackground} />
<div className="sidebar-wrapper">
<div className="logo">
<a href="/" className="simple-text">
<img
src="../../images/favicon.png"
style={{ maxHeight: "50px" }}
/>
Trafficfine
</a>
</div>
<ul className="nav">
<li className="nav-item active">
<a className="nav-link" href="/admin/dashbord">
<i className="fas fa-tachometer-alt" />
<p>Dashboard</p>
</a>
</li>
<li className="nav-item">
<a className="nav-link" href="/admin/officers">
<i className="fas fa-briefcase" />
<p>Officers</p>
</a>
</li>
<li>
<a className="nav-link" href="/admin/offences">
<i className="fas fa-times-circle" />
<p>Offences</p>
</a>
</li>
<li>
<a className="nav-link" href="/admin/drivers">
<i className="fas fa-bus-alt" />
<p>Drivers</p>
</a>
</li>
</ul>
</div>
</div>
);
}
}
export default Sidebar;
I want to change the active class dynamically when a user is clicking on the nav Item and add some styling to the active class. I saw some similar questions have been asked on the stack overflow and I tried those example. But through those, I was unable to achieve that. Can someone help me to solve my problem by modifying
my code? Thank you.
You already have your target class in state, you just need to add it like this
<div className={"sidebar " + this.state.activeTabClassName} data-image={imagine} id="sidebar">
And call this.setState( {activeTabClassName: "newActiveClass"} ) when you want to change it.
I am new to ReactJS and I am trying to make a menu that by pressing any of the functions the active class will disappear and the new page will appear. In here for instance, I am trying to click on My Order and get forwarded to the page I asked to load. How do I make this correctly? Here is my current code:
import React from 'react';
import ReactDOM from 'react-dom';
import "./index.css";
class MainPanel extends React.Component {
render() {
return (
<div className="main-layout">
<header>
<ul className="top">
<h1>Header</h1>
</ul>
</header>
<ul className="categories">
<li>Main Panel</li>
<li onClick={<MyOrder />}>My Order</li>
<li>Technical Support</li>
<li>My Payments</li>
<li>Suggestions/ Questions</li>
</ul>
</div>
);
}
}
function MyOrder () {
return (
<div className="main-layout">
<header>
<ul className="top">
<h1>My Order</h1>
</ul>
</header>
<ul className="categories">
<li>Where is my order?</li>
<li>My order delays more than the expected time</li>
<li>My order status shows that the order arrived but it did not</li>
<li>I have a complaint</li>
<li>Suggestions/ Questions</li>
</ul>
</div>
);
}
ReactDOM.render(
<MainPanel />,
document.getElementById('root')
);
Without React Router and other 3rd party libraries you could do something like this:
class Overview extends React.Component {
onMenuClick(id) {
return this.props.onMenuClick(id);
}
render() {
return(
<ul className="categories">
<li onClick={this.onMenuClick.bind(this, "mainPanel")}>Main Panel</li>
<li onClick={this.onMenuClick.bind(this, "myOrder")}>My Order</li>
<li onClick={this.onMenuClick.bind(this, "technicalSupport")}>Technical Support</li>
<li onClick={this.onMenuClick.bind(this, "myPayments")}>My Payments</li>
<li onClick={this.onMenuClick.bind(this, "suggestions")}>Suggestions/ Questions</li>
</ul>
);
}
}
class MainPanel extends React.Component {
// sets the initial value for this.state.page
componentWillMount() {
this.setState({
page: "overview"
});
}
switchPage(id) {
this.setState({ page: id });
}
showComponent() {
if(this.state.page === "overview") return (<Overview
onMenuClick={::this.switchPage}
/>);
if(this.state.page === "myOrder") return <MyOrder />;
throw new Error(`${this.state.page} is not a valid page id`);
}
render() {
return (
<div className="main-layout">
<header>
<ul className="top">
<h1>Header</h1>
</ul>
</header>
{ this.showComponent() }
</div>
);
}
}
You change the view by updating the state. Depending on the state different components are mounted/unmounted.
Note based on my experience: Try to handle your app state (in our case the current page information) via React Baobab or something like this (centralized state) because otherwise all these props bubblings become confusing.
I have a React-Redux application, and I have created a "Sidebar" component in which I would like to toggle 'active' class onClick of each Menu item.
The current code that I have toggles the 'active' class on all the menu items.
Here is my code:
import React, {Component} from 'react'
import {connect} from 'react-redux'
export default class Sidebar extends Component {
constructor(props) {
super(props)
this.toggleClass= this.toggleClass.bind(this);
this.state = {
activeIndex: false
}
}
toggleClass(e) {
const currentState = this.state.activeIndex;
this.setState({ activeIndex: !currentState });
};
render(){
return(
<div id="sidebar">
<div className="nav">
<ul className="dashboard-menu">
{this.renderSidebarMenuItems}
<li className={this.state.activeIndex ? 'active': null} onClick={this.toggleClass}>Menu item 1</li>
<li className={this.state.activeIndex ? 'active': null} onClick={this.toggleClass}>Menu item 2</li>
<li className={this.state.activeIndex ? 'active': null} onClick={this.toggleClass}>Menu item 3</li>
<li className={this.state.activeIndex ? 'active': null} onClick={this.toggleClass}>Menu item 4</li>
</ul>
</div>
</div>
)
}
}
I need a solution such that onClick of each menu item only that elements class changes to 'active' and all other menu items go back empty class.
Thank you
your activeIndex should be a index number or key,like this:
import React, {Component} from 'react'
import {connect} from 'react-redux'
export default class Sidebar extends Component {
constructor(props) {
super(props)
this.toggleClass= this.toggleClass.bind(this);
this.state = {
activeIndex: 0
}
}
toggleClass(index, e) {
this.setState({ activeIndex: index });
};
render(){
return(
<div id="sidebar">
<div className="nav">
<ul className="dashboard-menu">
{this.renderSidebarMenuItems}
<li className={this.state.activeIndex==0 ? 'active': null} onClick={this.toggleClass.bind(this, 0)}>Menu item 1</li>
<li className={this.state.activeIndex==1 ? 'active': null} onClick={this.toggleClass.bind(this, 1)}>Menu item 2</li>
<li className={this.state.activeIndex==2 ? 'active': null} onClick={this.toggleClass.bind(this, 2)}>Menu item 3</li>
<li className={this.state.activeIndex==3 ? 'active': null} onClick={this.toggleClass.bind(this, 3)}>Menu item 4</li>
</ul>
</div>
</div>
)
}
}