Toggle border and select onClick in react



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;

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;


Source: stackoverflow