'How to add styles to individual elements in react using e.target, when a button is clicked?
I am trying to add styles to the inidividual elements. I want when an individual div( is clicked to make sure that the paragraph of the specific changes from display: none to dislay:block. But the problem is, when I click only on one , all the paragraph text is displayed. here is the css below:
.cards{
background-color: red;
display: flex;
justify-content: center;
align-items: center;
height: 20vh;
}
[class*=cardDisplay]{
height: 80%;
display: flex;
align-items: center;
justify-content: center;
width: 200px;
background: black;
color: white;
margin: auto;
}
[class*=card-content]{
display: none;
}
[class*=card-content-2]{
display: block;
}
and the react.js file:
import React from 'react';
import {useState} from "react";
import "./game.css";
function Game() {
const [styling, setStyling] = useState("card-content")
const handleClick = () => {
setStyling("card-content-2")
}
return (
<div className="cards">
<div className="cardDisplay card-1" onClick={handleClick}>
<p className={styling}>Win</p>
</div>
<div className="cardDisplay card-2" onClick={handleClick}>
<p className={styling}>Sorry, No Win</p>
</div>
<div className="cardDisplay card-3" >
<p className={styling} onClick={handleClick}>Sorry, No Win</p>
</div>
</div>
)
}
Solution 1:[1]
You're using only one styling that you're applying to all paragraphs. If you want distinct styling for each paragraph, you have to hold that state separately for each paragraph.
Either:
Make the
div+paragrapha component that holds its own state, orHave multiple
stylingstate members (perhaps an array).
I would lean toward the first:
function Card({className = "", children}) {
const [styling, setStyling] = useState("card-content");
const handleClick = () => {
setStyling("card-content-2")
};
return (
<div className={`cardDisplay ${className}`} onClick={handleClick}>
<p className={styling}>{children}</p>
</div>
);
};
function Game() {
return (
<div className="cards">
<Card className="card-1">Win</Card>
<Card className="card-2">Sorry, No Win</Card>
<Card className="card-3">Sorry, No Win</Card>
</div>
);
}
There's lots of ways to spin that, but that's the basic idea.
But there's also an argument for the cards being an array of objects with state; here's an example with the results randomized when the component is first mounted:
function makeCards() {
const num = 3;
const win = Math.floor(Math.random() * num);
return Array.from({length: 3}, (_, index) => ({
id: `card-${index}`,
result: index === win ? "Win" : "Sorry, No Win",
showing: false,
}));
}
function Game() {
const [cards, setCards] = useState(makeCards);
const handleClick = (event) => {
const id = event.currentTarget.getAttribute("data-id");
setCards(prevCards => {
const newCards = prevCards.map(card => {
if (card.id === id) {
return {...card, showing: true};
}
return card;
});
return newCards;
});
};
return (
<div className="cards">
{cards.map(({id, result, showing}) => (
<div key={id} data-id={id} className={`cardDisplay ${id}`} onClick={handleClick}>
<p className={showing ? "card-content" : "card-content-2"}>{result}</p>
</div>
))}
</div>
);
}
Solution 2:[2]
This may help you. It really works........
import React from 'react';
import {useState} from "react";
import "./game.css";
function Game() {
const handleClick = (e) => {
e.target.firstChild?.classList?.remove("card-content");
e.target.firstChild?.classList?.add("card-content-2");
};
return (
<div className="cards">
<div className="cardDisplay card-1" onClick={handleClick}>
<p className="card-content">Win</p>
</div>
<div className="cardDisplay card-2" onClick={handleClick}>
<p className="card-content">Sorry, No Win</p>
</div>
<div className="cardDisplay card-3" onClick={handleClick}>
<p className="card-content">Sorry, No Win</p>
</div>
</div>
);
}
Solution 3:[3]
What you are currently doing is changing the styling for each of the p tags.
I will advise you have a custom class that returns your div tag that contains the p tag
Have an array of Objects that contain the card style and the text that will be displayed. Map through the array and return the style and tags accordingly. As displayed below.
handle the click events in the custom div.
import React from 'react';
import "./game.css";
import MyDiv from './MyDiv';
const cards = [{ cardStyle: 'card-1', text: "Win" },
{ cardStyle: 'card-2', text: 'Sorry, No Win' },
{ cardStyle: 'card-3', text: 'Sorry, NoWin' }];
function Game() {
return (
<div className="cards">
{cards.map((card, index) =>
(<MyDiv cardNumberStyle={card.cardStyle}
key={index}
textToDisplay={card.text} />))
}
</div>
);
}
export default Game;
And then MyDiv is:
import React, { useState } from "react";
const MyDiv = ({ cardNumberStyle, textToDisplay }) => {
const [styling, setStyling] = useState('card-content');
///Handles clicks
const handleClick = () => {
//conditionally change the styling
if (styling === 'card-content')
setStyling('card-content-2')
else setStyling('card-content');
}
return (
<div className={`cardDisplay ${cardNumberStyle}`} onClick={handleClick}>
<p className={styling}>{textToDisplay}</p>
</div>
);
}
export default MyDiv;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Tariqul Islam |
| Solution 3 | devKing_ernest |
