I am trying to use hooks to change react state onClick. I used .map to make a list of “cards” with different props and I want to make that into a form where I can click on 1 of the cards and the border/css will change and the card will be selected.
I’m not sure if I should put the hook for this in the page and pass to the component or put it directly in the component. (right now I have select in page and style in component, but it isn’t working)
So far I can get the color to change on click, but if I click on another card it doesn’t change the other one back. I have a few pages I have to do something similar to this on so any advice is appreciated!
Here is code for page:
const LemmeUpgradeYa = () => {
const [path, setPath] = useState('/');
const cardSelector = () => {
// setPath('/${plans.plan}');
console.log(AllPlans.AllPlans);
};
useEffect(() => {
cardSelector();
});
return (
<React.Fragment>
<Card>
<style>
@import url('https://fonts.googleapis.com/css2?family=Martel+Sans:wght@300&display=swap');
</style>
<CardBody className="big-card-plan">
<h1 className="plan-title-one">Upgrade Plan</h1>
<Form>
{AllPlans.AllPlans.map((planItem) => (
<Cards onClick={cardSelector} key={planItem} {planItem} />
))}
<a href={path}>Continue</a>
</Form>
</CardBody>
</Card>
</React.Fragment>
);
};
export default LemmeUpgradeYa;
here is code for componenet:
const Cards = (plans) => {
const [border, setBorder] = useState('profile-box-one');
const cardSelector = () => {
setBorder('profile-box-two');
setPath('/${plans.plan}');
};
const selectChange = () => {
setBorder('profile-box-one');
};
useEffect(() => {
selectChange();
}, []);
return (
<React.Fragment>
<Card className={border} onClick={cardSelector} onChange={selectChange}>
<Row>
<Col className="float-left max-width-plan">
<div className="plan-selector">Current Plan:</div>
<div className="center-text plan-font">{plans.plan}</div>
</Col>
<Col className="float-right padding-plan-top">
<Row>
<Col className="max-plan-width">
<p className="plan-description">{plans.description}</p>
</Col>
<Col>
<div className="plan-price">${plans.price} / month</div>
</Col>
</Row>
</Col>
</Row>
</Card>
</React.Fragment>
);
};
export default Cards;
Advertisement
Answer
The common approach is to have a state at Parent
that holds the selected child id, you pass down to each Child
the current selected and the function to select . At child you can compare if it was selected to pick the right CSS class.
obs: at Cards
you are naming props
as plans
. though you can name however you want, it’s standard to stay with the convention and call it as props
.
below it’s how you can handle the issue applied to your code:
const LemmeUpgradeYa = () => {
const [pickedCard, setPickedCard] = useState(null);
return (
<React.Fragment>
<Card>
<style>
@import url('https://fonts.googleapis.com/css2?family=Martel+Sans:wght@300&display=swap');
</style>
<CardBody className="big-card-plan">
<h1 className="plan-title-one">Upgrade Plan</h1>
<Form>
{AllPlans.AllPlans.map((planItem) => (
<Cards pickedCard={pickedCard} setPickedCard={setPickedCard} key={planItem} plans={planItem} />
))}
<a href={path}>Continue</a>
</Form>
</CardBody>
</Card>
</React.Fragment>
);
};
export default LemmeUpgradeYa;
const Cards = ({ plans, pickedCard, setPickedCard }) => {
const cardSelector = () => {
setPickedCard(plans.plan);
setPath('/${plans.plan}');
};
const selectChange = () => {
setPickedCard(null);
};
return (
<React.Fragment>
<Card className={`profile-box-${pickedCard ? 'two' : 'one' }`} onClick={cardSelector} onChange={selectChange}>
<Row>
<Col className="float-left max-width-plan">
<div className="plan-selector">Current Plan:</div>
<div className="center-text plan-font">{plans.plan}</div>
</Col>
<Col className="float-right padding-plan-top">
<Row>
<Col className="max-plan-width">
<p className="plan-description">{plans.description}</p>
</Col>
<Col>
<div className="plan-price">${plans.price} / month</div>
</Col>
</Row>
</Col>
</Row>
</Card>
</React.Fragment>
);
};
export default Cards;