React add class when clicked to only 1 li - javascript

I am trying to add the class sub-menu-open to a li when its clicked which will then open a submenu. however the li's are dynamically generated and theres about 6 of them. When i click on an li its successfully adding the class to the li however its adding the class to all the li's now just the one clicked. Can yall help me figure out how to get the class to only stick the the li thats clicked?
const [isActive, setActive] = useState(false);
const toggleClass = () => {
setActive(!isActive);
};
return (
<>
{menus.map((menuItem, i) => {
return (
<li className={"mobile-menu-item menu-item-has-children" + (isActive? ' sub-menu-open': null)} onClick={toggleClass}>
...

Update the li
<li
className={"mobile-menu-item menu-item-has-children" + (
isActive == i
? ' sub-menu-open'
: null
)}
onClick={() => toggleClass(i)}>
Then update the function like bellow
const toggleClass = (index) => {
setActive(index);
};
Now update the state like bellow
const [isActive, setActive] = useState(null);

Related

Unable to Deselect the Previous item, when clicked on another Item using Reactjs

I have list of items and I am changing the background color when I clicked on that item...
I need to change only the current Selected Item only , Previous selected Item should deselect... Now here, all items are getting changed when I clicked on each item... How can I solve this?? Can anyone help me in this ??
Here is my code
const Time = () => {
const [selectedItem, setSelectedItem] = React.useState();
const handleSelect = (event,selectedItem) => {
setSelectedItem(selectedItem);
event.target.style.backgroundColor = 'black';
event.target.style.color = 'white';
};
const dataTime = useMemo(() => TimeData, []);
const chunks = useMemo(() => {
const _chunks = [];
const tmp = [...dataTime];
while (tmp.length) {
_chunks.push(tmp.splice(0, 3));
}
//console.log(_chunks);
return _chunks;
}, [dataTime]);
return (
<div className="Main-Section">
<div className="First-Section">Time</div>
<div className="Second-Section">
<div className="date_title">Wednesday , June 13</div>
<div className="time_Slots">
{chunks.map((timeslot) => {
return (
<div key={timeslot} className="inline">
{timeslot.map((time) => {
return <p className='timeslots target' key={time}
onClick={(event) => handleSelect(event,time)}>{time}</p>;
})}
</div>
);
})}
</div>
<div>{selectedItem}</div>
<div className='new_Date'>PICK A NEW DATE</div>
</div>
</div>
);
};
U can struct Ur time data to an object like this...
{text:"",selected:false}
and use selected property flag in data then assign a class conditionally into items based on that flag. then in clicking iterate Ur list and make all the flags false except the selected one.
function selectFn(selectedItem) {
data.forEach((item) => {
item.selected = false;
});
selectedItem.selected = true;
}
and UR template be some
...
{chunks.map((timeslot) => {
return (
<div key={timeslot} className="inline">
{timeslot.map((time) => {
return <p className={`timeslots target ${time.selected ? "selectedClass" : ""}`} key={time.text}
onClick={(event) => selectFn(time)}>{time.text}</p>;
})}
</div>
);
})}
...
the css stuff..
.selectedClass{
background:black;
color:white;
}
you have to first change color for all the element to default color. Then you have to change the current element color to desired color.

addClass only once onClick ReactJS

Hi I'm new to ReactJS so I'm importing some work of mine to my project and turning it into components. I have a span acting as a button with keyframe animations, but when i load the page it gets animated.
One solution i have is to make a .class.animation and give the .animation class on the first click.
The thing is that I know how to code it in jquery but not on react.
The idea is to convert this into react:
$('.navTrigger').onClick(function () {
$(this).addClass('animations');
});
Right now I have this:
const [isActive, setActive] = useState("false");
const handleToggle = () => {
setActive(!isActive);
};
return (
<span onClick={handleToggle} className={`navTrigger ${isActive ? "" : "animations"} ${isActive ? "" : "active"}`}>
<i></i>
<i></i>
<i></i>
</span>
);
I have a function where i toggle the active class to run backward and forward animations.
What the code below does is on web load, the span starts with navTrigger class. The first time you click it its's given animations and active class. And then if you interact with it again it takes out active class and leaves animations there
function MenuButton() {
const [isActive, setActive] = useState(false);
const [animating, setAnimating] = useState(false);
const handleToggle = () => {
setActive(!isActive);
setAnimating(true);
};
return (
<span onClick={handleToggle} className={`navTrigger ${animating ? "animations" : ""} ${isActive ? "active" : ""}`}>
<i></i>
<i></i>
<i></i>
</span>
);
}

How to show single hidden element of list and hide the rest

I have a column list of elements, and each of them has hidden div, I want to show hidden element on click, but when I'm clicking another div, I want to hide current and show the one I clicked last, how can I do it correctly?
You could have two specific classes, one that hides element and one that shows element. when clicking on the element you can use jQuery or JavaScript to toggle the class that shows element for the hidden div of that specific element and hide everything for any other div.
The component you're rendering could take in an active prop and only render the second div if this prop is true.
With this, you could then keep track of which element is selected in the parent.
I threw together a working example with very simple content
import React, { useState } from 'react';
const ListItem = ({id, isActive, handleClick}) => {
return (
<div id={id} onClick={handleClick}>
Here is the element
{!!isActive && <div>I am the selected element</div>}
</div>
);
};
export const List = () => {
const [selectedItem, setSelectedItem] = useState();
const items = ['one', 'two', 'three'];
const handleClick = (event) => {
setSelectedItem(event.target.id);
}
return (
<div>
{items.map(item => (
<ListItem id={item} isActive={item===selectedItem} handleClick={handleClick}/>
))}
</div>
)
}

React - change state of one button from 100 buttons array, and reset state of all buttons on one click

So, I have 100 mapped buttons from array, something like that
{
buttons.map((button, index) =>
<StyledGameButton
key={index}
value={button}
onClick={this.checkButton}>
{ button < 10 ? `0${button}` : button }
</StyledGameButton>
)
}
I want user to click all the buttons from 0 to 99, so when he click for example 0 the button should change color. I made function checking if he clicked correct button, and if yes then I am addind data-attr to that button (thats how I am changing the color of buttons):
checkButton = e => {
const buttonId = e.currentTarget.getAttribute('value');
const nextButton = this.state.currentButton === null ? 0 : this.state.currentButton + 1;
if (buttonId == nextButton){
this.setState({
currentButton: parseInt(buttonId),
});
if (this.state.currentButton === 99) {
this.gameEnd();
};
e.currentTarget.setAttribute('data-status', 'correct');
}
}
The problem is that I want to make reset button, that will change all buttons to 'unclicked' so I have to delete data-attr from all buttons on one click. How can I do this? Or is there a better solution to manage 'state' of single button without making 100 states?
100 checkboxes demo
use an Array to store the state would be fine.
const list = [...Array(100).keys()].map(x => ({ id: x }));
const App = () => {
const [selected, setSelected] = React.useState([]); // init with empty list
const onChangeHandler = id => () => { // pass index/identify params
selected.includes(id) // check whether been checked
? setSelected(selected.filter(x => x !== id)) // yes, remove
: setSelected([...selected, id]); // no, add
};
const onRemove = () => {
setSelected([]); // remove all, set to empty list
};
return (
<div className="App">
{list.map(item => (
<input
type="checkbox"
key={item.id}
checked={selected.includes(item.id)}
onChange={onChangeHandler(item.id)}
/>
))}
<br />
<button onClick={onRemove}>Remove all</button>
<div>{selected.join(",")}</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

How to focus on a list item with useRef react hook

I have a dynamically generated array of list items
const ArtistProfile = props => {
// api data
const tracks = props.data.artistTopTracks && props.data.artistTopTracks.tracks
const [songs, setSongs] = useState(null)
const songRef = useRef(null)
// effect hook that creates list of SongListItem components
useEffect(() => {
if (tracks) {
const trackTags = tracks.map((track, index) => {
if (index > 4) return
return (
<SongListItem ref={songRef} role="button" key={track.id} onClick={() => songRef.current.focus()}>
<SongTag
image={track.album.images[1].url}
duration={msToTime(track.duration_ms)}
name={track.name}
explicit={track.explicit}
/>
</SongListItem>
)
})
setSongs(trackTags)
}
}, [tracks])
return (
<ArtistProfileContainer>
<ul>{songs}</ul>
</ArtistProfileContainer>
)
}
Im trying to use the onClick event to focus on one item in the list. All my list items are passed this ref const songRef = useRef(null) and I'm using the songRef.current property to focus on the element I'm clicking on. This isn't focusing on anything when clicking so none of my styles are changing.
const SongListItem = styled.li`
background-color: #1d1d1d;
:focus {
svg {
opacity: 0.7;
}
background-color: #181818;
}
`
I'm trying to achieve the same results you can see on this Spotify link https://open.spotify.com/artist/5K4W6rqBFWDnAN6FQUkS6x
If you hover over the "Popular" songs you see the styles change temporarily, but once you click it keeps the changes until you click another song.
You just can't focus on li:
https://stackoverflow.com/a/30213871/7763883
Add
<li tabIndex="-1" ...
And it will work.
There are tabIndex's in your example.

Categories