Tėvinio komponento būsenos keitimas vaikiniame komponente React

Ankstesnėje pamokoje mūsų duomenų būsena buvo saugoma tėviniame komponente, o vaikiniai komponentai gaudavo šiuos duomenis kaip props.

Tarkime, dabar norime keisti savo produktus. Sukurkime, pavyzdžiui, mygtuką, kuris įdės mūsų produktą į krepšelį. Pirmiausia į mūsų produktų masyvą pridėkime lauką inCart, rodantį, ar produktas yra krepšelyje, ar 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},
];

Products komponente į produkto žymą pridėkime dar vieną 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>;
}

Vaikiniame komponente Product sukurkime informacijos apie krepšelį išvedimą ir mygtuką pridėjimui į krepšelį:

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

Įgyvendinkime pridėjimą

Pagal React taisykles komponentas neturėtų keisti savo props. Tai reiškia, kad vaikinis komponentas negali pats save įdėti į krepšelį, pakeisdamas props inCart. Tai neteisinga.

Teisinga būtų paprašyti tėvinio komponento pakeisti savo būseną prods, įdėjus tam tikrą produktą į krepšelį.

Pažiūrėkime, kaip tai daroma.

Tėviniame komponente sukurkime funkciją addToCart, kuri parametru priima id produkto ir šiam produktui keičia savybę inCart į true:

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

Į produkto žymą pridėkime atributą, į kurį perduosime mūsų sukurtą funkciją, taip pat atributą, į kurį perduosime produkto 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}
  />;
});

Kaip matote, į komponentų props galima perduoti ne tik kokius nors duomenis, bet ir funkcijas.

Galutinis Products klasės kodas bus toks:

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

Dabar vaikinėje klasėje mums bus prieinama funkcija addToCart. Iškvieskime šią funkciją paspaudus mygtuką, perduodant jai parametru produkto id:

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

Pasirodo, kad paspaudus mygtuką vaikiniame komponente būs iškviesta tėvinio komponento funkcija, kuri ir pakeis tėvinio komponento būseną. Tėvinio komponento būsenos pakeitimas sukels perrenderinimą ir perbraižys mūsų produktą, perduodant jam pakeistą props.

Задание 1

Paimkite komponentą User iš ankstesnės pamokos. Padarykite taip, kad jame atsirastų mygtukas vartotojo užblokavimui.