1

I'm having some issues with child re-rendering, I pass methods to children to see if a button should be displayed or not but when the state of the parent changes, the children are not re-rendered.

I tried with the disabled attribute for the button but didn't work either.

Here's my code (I removed unnecessary part):

function Cards(props) {
  const isCardInDeck = (translationKey) => {
    return props.deck.some(
      (card) => !!card && card.translationKey === translationKey
    );
  };

  const addToDeck = (card) => {
    if (!isCardInDeck(card.translationKey) && !!card) {
      props.deck.push(card);
    }
  };

  const removeFromDeck = (card) => {
    if (isCardInDeck(card.translationKey) && !!card) {
      var index = props.deck.findIndex(
        (c) => c.translationKey === card.translationKey
      );
      props.deck.splice(index, 1);
    }
  };

  return (
    <div className="cardsContent">
      <div className="cards">
        {cardList.length > 0 ? (
          cardList.map((item, index) => {
            return (
              <Card key={index} card={item} addToDeckDisabled={isCardInDeck(item.translationKey)} addToDeckClick={addToDeck} removeFromDeckClick={removeFromDeck} />
            );
          })
        ) : (
          <span>
            <FormattedMessage id="app.cards.label.no.card.found" defaultMessage="No card found with filter."/>
          </span>
        )}
      </div>
    </div>
    );
}

function Card(props) {

  const toggleShowDescription = () => {
    if (!showDescription) {
      setShowDescription(!showDescription);
    }
  };

  return (
    <div onClick={toggleShowDescription} onBlur={toggleShowDescription} >
      <img src={"../images/cards/" + props.card.image} alt={props.card.image + " not found"} />
      {showDescription ? (
        <div className="customCardDetail">
          <div className="cardName"></div>
          <div className="cardType">
            {props.addToDeckDisabled ? (
              <Button onClick={() => { props.removeFromDeckClick(props.card);}} startIcon={<RemoveIcon />}>
                Remove from deck
              </Button>
            ) : (
              <Button onClick={() => { props.addToDeckClick(props.card); }} startIcon={<AddIcon />}>
                Add to deck
              </Button>
            )}
          </div>
          <div className="cardDescription">
            <span>
              <FormattedMessage id={props.card.description} defaultMessage={props.card.description} />
            </span>
          </div>
        </div>
      ) : (
        ""
      )}
    </div>
  );
}
AnthonyDa
  • 493
  • 15
  • 34

1 Answers1

1

You code does not update state. Cards mutates the props that it is receiving. To use state in a functional component in React you should use the useState hook.

Cards would then look something like this:

function Cards(props) {
  const [deck, setDeck] = useState(props.initialDeck)

  const isCardInDeck = (translationKey) => {
    return deck.some(
      (card) => !!card && card.translationKey === translationKey
    );
  };

  const addToDeck = (card) => {
    if (!isCardInDeck(card.translationKey) && !!card) {
      setDeck([...deck, card])
    }
  };

  const removeFromDeck = (card) => {
    if (isCardInDeck(card.translationKey) && !!card) {
      setDeck(deck.filter(deckItem => deckItem.translationKey !== card.translationKey))
    }
  };

  return (
    <div className="cardsContent">
      <div className="cards">
        {cardList.length > 0 ? (
          cardList.map((item, index) => {
            return (
              <Card key={index} card={item} addToDeckDisabled={isCardInDeck(item.translationKey)} addToDeckClick={addToDeck} removeFromDeckClick={removeFromDeck} />
            );
          })
        ) : (
          <span>
            <FormattedMessage id="app.cards.label.no.card.found" defaultMessage="No card found with filter."/>
          </span>
        )}
      </div>
    </div>
    );
}
thedude
  • 9,388
  • 1
  • 29
  • 30
  • Does the props coming from Cards' parent will be modified still? Because it's used in another component. – AnthonyDa Oct 22 '20 at 12:23
  • No, props should not be mutated like this. if you need this state somewhere else try [lifting the state](https://reactjs.org/docs/lifting-state-up.html) – thedude Oct 22 '20 at 12:25
  • Not very familiar with this but I'll check. I might also put the methods that manipulate the deck in the component where it's declared? Which is best? – AnthonyDa Oct 22 '20 at 12:30