Vanema komponendi olemu muutmine lapse komponendis Reactis

Eelmises õppetükis oli meil andmetega olek hoitud vanema komponendis ning lapse komponendid saidsid need andmed propidena.

Oletame nüüd, et tahame oma tooteid muuta. Teeme näiteks nupu, mis paneb meie toote ostukorvi. Alustuseks lisame oma toodete massiivi välja inCart, mis näitab, kas toode on ostukorvis või mitte:

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

Komponendis Products lisame toote tegile veel ühe atribuudi 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>;
}

Teeme lapse komponendis Product ostukorvi kohta teabe kuvamise ja nupu ostukorvi lisamiseks:

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

Rakendame lisamise

React'i reeglite kohaselt komponent ei tohiks muuta oma propse. See tähendab, et lapse komponent ei saa ise ennast ostukorvi panna, muutes propsi inCart. See ei ole õige.

Õige on paluda vanema komponendil muuta oma olekut prods, pannes kindla toote ostukorvi.

Vaatame, kuidas seda tehakse.

Vanema komponendis teeme funktsiooni addToCart, mis parameetrina võtab vastu id toote ja selle toote puhul muudab omadust inCart väärtusele true:

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

Toote tegile lisame atribuudi, millesse edastame meie loodud funktsiooni, samuti atribuudi, millesse edastame toote id:

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

Nagu näete, saab komponentide propstesse edastada mitte ainult mingeid andmeid, vaid ka funktsioone.

Lõplik Products klassi kood saab järgmine:

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

Nüüd on lapse klassis meil kättesaadav funktsioon addToCart. Kutsume selle funktsiooni esile nupu klõpsul, edastades sellele parameetrina id toote:

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

Tulemuseks on, et nupu klõpsul lapse komponendis kutsutakse esile vanema funktsioon, mis muudabki vanema olekut. Vanema oleku muutmine põhjustab uuesti renderdamise ja joonistab meie toote uuesti, edastades sellele muudetud propsi.

Задание 1

Võtke komponent User eelmisest õppetükist. Tehke nii, et selles ilmub nupp kasutaja banimiseks.