Promena stanja roditelja u podređenoj komponenti u React-u

U prethodnoj lekciji naše stanje sa podacima je čuvano u roditeljskoj komponenti, a podređene komponente su dobijale te podatke u vidu prosledjenih vrednosti (props).

Recimo sada da želimo da menjamo naše proizvode. Hajde da napravimo, na primer, dugme koje će dodavati naš proizvod u korpu. Za početak hajde da dodamo u naš niz sa proizvodima polje inCart koje pokazuje da li je proizvod u korpi ili ne:

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},
];

U komponenti Products u tag za proizvod dodajmo još jedan atribut 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>;
}

Hajde da u podređenoj komponenti Product realizujemo prikaz informacije o korpi i dugme za dodavanje u korpu:

jsxfunction Product({ id, name, cost, inCart }) {
  return <div>
    name: <span>{name}</span>,
    cost: <span>{cost}</span>,
    <span>{inCart ? 'u korpi' : 'nije u korpi'}</span>
    <button>u korpu</button>
  </div>;
}

Realizujmo dodavanje

Prema pravilima React-a, komponenta ne treba da menja svoje prosledjene vrednosti (props). To znači da podređena komponenta ne može sama sebe dodati u korpu, menjajući prosledjenu vrednost inCart. To nije ispravno.

Ispravno je zamoliti roditeljsku komponentu da promeni svoje stanje prods, dodajući određeni proizvod u korpu.

Hajde da vidimo kako se to radi.

U komponenti-roditelju napravimo funkciju addToCart, koja kao parametar prihvata id proizvoda i za taj proizvod menja svojstvo inCart na true:

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

U tag za proizvod dodajmo atribut, u koji prosledimo našu kreiranu funkciju, kao i atribut, u koji prosledimo id proizvoda:

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

Kao što vidite, u prosledjene vrednosti komponenti možete proslediti ne samo neke podatke, već i funkcije.

Završni kod komponente Products će biti sledeći:

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>;
}

Sada će u podređenoj komponenti biti dostupna funkcija addToCart. Pozovimo ovu funkciju klikom na dugme, prosledivši joj kao parametar id proizvoda:

jsxfunction Product({ id, name, cost, inCart, addToCart }) {
  return <div>
    name: <span>{name}</span>,
    cost: <span>{cost}</span>,
    <span>{inCart ? 'u korpi' : 'nije u korpi'}</span>
    <button onClick={() => addToCart(id)}>u korpu</button>
  </div>;
}

Ispostavlja se da će klikom na dugme u potomku biti pozvana funkcija roditelja, koja će i promeniti stanje roditelja. Promena roditeljskog stanja će pokrenuti ponovno renderovanje i ponovo će nacrtati naš proizvod, prosledivši mu izmenjenu prosledjenu vrednost.

Задание 1

Uzmite komponentu User iz prethodne lekcije. Uredite je tako da se u njoj pojavi dugme za banovanje korisnika.