Zmena stavu rodiča v dcérskom komponente v React

V predchádzajúcej lekcii sme mali stav s údajmi uložený v rodičovskom komponente a dcérske komponenty tieto údaje dostávali vo forme props.

Teraz povedzme, že chceme naše produkty meniť. Urobme napríklad tlačidlo, ktoré bude umiestňovať náš produkt do košíka. Na začiatok poďme do nášho poľa s produktmi pridať pole inCart, ktoré ukazuje, či je produkt v košíku alebo nie:

jsxconst initProds = [
  {id: id(), name: 'product1', cost: 100, inCart: false},
  {id: id(), name: 'product2', cost: 200, inCart: false},
  {id: id(), name: 'product3', cost: 300, inCart: false},
];

V komponente Products do tagu s produktom pridajme ešte jeden atribút inCart:

jsxfunction Products() {
  const [prods, setProds] = useState(initProds);
  
  const items = prods.map(prod => {
    return <Product
      key   ={prod.id}
      name  ={prod.name}
      cost  ={prod.cost}
      inCart={prod.inCart}
    />;
  });
  
  return <div>
    {items}
  </div>;
}

Poďme v dcérskom komponente Product urobiť výpis informácií o košíku a tlačidlo na pridanie do košíka:

jsxfunction Product({ id, name, cost, inCart }) {
  return <div>
    name: <span>{name}</span>,
    cost: <span>{cost}</span>,
    <span>{inCart ? 'in cart' : 'not in cart'}</span>
    <button>to cart</button>
  </div>;
}

Realizujme pridanie

Podľa pravidiel React komponent by nemal meniť svoje props. To znamená, že dcérsky komponent nemôže sám seba vložiť do košíka zmenou props inCart. To nie je správne.

Správne bude požiadať rodičovský komponent, aby zmenil svoj stav prods, vložil určitý produkt do košíka.

Pozrime sa, ako sa to robí.

V komponente-rodičovi urobme funkciu addToCart, ktorá parametrom prijíma id produktu a pre tento produkt mení vlastnosť inCart na true:

jsxfunction addToCart(id) {
  setProds(prods.map(prod => {
    if (prod.id === id) {
      prod.inCart = true;
    }
    
    return prod;
  }));
}

Do tagu s produktom pridajme atribút, do ktorého odošleme našu vytvorenú funkciu, a tiež atribút, do ktorého odošleme id produktu:

jsxconst items = prods.map(prod => {
  return <Product
    key      ={prod.id}
    id       ={prod.id}
    name     ={prod.name}
    cost     ={prod.cost}
    inCart   ={prod.inCart}
    addToCart={addToCart}
  />;
});

Ako vidíte, do props komponentov je možné odosielať nielen nejaké údaje, ale aj funkcie.

Výsledný kód triedy Products bude nasledovný:

jsxfunction Products() {
  const [prods, setProds] = useState(initProds);
  
  function addToCart(id) {
    setProds(prods.map(prod => {
      if (prod.id === id) {
        prod.inCart = true;
      }
      
      return prod;
    }));
  }
  
  const items = prods.map(prod => {
    return <Product
      key      ={prod.id}
      id       ={prod.id}
      name     ={prod.name}
      cost     ={prod.cost}
      inCart   ={prod.inCart}
      addToCart={addToCart}
    />;
  });
  
  return <div>
    {items}
  </div>;
}

Teraz v dcérskej triede budeme mať prístupnú funkciu addToCart. Zavolajme túto funkciu kliknutím na tlačidlo, odovzdajúc jej parametrom id produktu:

jsxfunction Product({ id, name, cost, inCart, addToCart }) {
  return <div>
    name: <span>{name}</span>,
    cost: <span>{cost}</span>,
    <span>{inCart ? 'in cart' : 'not in cart'}</span>
    <button onClick={() => addToCart(id)}>to cart</button>
  </div>;
}

Výsledkom bude, že pri kliknutí na tlačidlo v potomkovi sa zavolá funkcia rodiča, ktorá zmení rodičovský stav. Zmena rodičovského stavu spôsobí prekreslenie a prekreslí náš produkt, odovzdajúc mu zmenený props.

Задание 1

Vezmite komponent User z predchádzajúcej lekcie. Urobte tak, aby sa v ňom objavilo tlačidlo na zabanovanie používateľa.