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;