Modificarea stării părintelui în componenta copil în React
În lecția anterioară, starea cu datele era stocată în componenta părinte, iar componentele copil primeau aceste date sub formă de props.
Să presupunem acum că vrem să ne modificăm produsele.
Să facem, de exemplu, un buton care va
plasa produsul nostru în coș. Pentru început
să adăugăm în matricea noastră cu produse
câmpul inCart, care indică dacă produsul
este în coș sau nu:
const 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},
];
În componenta Products în tag-ul cu produsul
să adăugăm încă un atribut inCart:
function 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>;
}
Să în componenta copil Product
facem o afișare a informației despre coș și un buton
pentru adăugarea în coș:
function 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>;
}
Să implementăm adăugarea
Conform regulilor React o componentă nu ar trebui
să-și modifice props-urile. Aceasta înseamnă că
componenta copil nu se poate pune singură
în coș, modificând prop-ul inCart.
Aceasta nu este corect.
Corect ar fi să cerem componentei părinte
să-și modifice starea prods, punând
un anumit produs în coș.
Să vedem cum se face acest lucru.
În componenta-părinte să facem funcția addToCart,
care ca parametru primește id-ul produsului
și pentru acel produs schimbă proprietatea inCart
în true:
function addToCart(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.inCart = true;
}
return prod;
}));
}
În tag-ul cu produsul să adăugăm un atribut, în care
transmitem funcția creată de noi, precum și
un atribut, în care transmitem id-ul produsului:
const items = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name ={prod.name}
cost ={prod.cost}
inCart ={prod.inCart}
addToCart={addToCart}
/>;
});
După cum vedeți, în props-urile componentelor se pot transmite nu numai unele date, ci și funcții.
Codul final al clasei Products va fi
următorul:
function 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>;
}
Acum în clasa copil vom avea acces la
funcția addToCart. Să apelăm această funcție
la click pe buton, transmitându-i ca parametru
id-ul produsului:
function 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>;
}
Se va întâmpla ca la click pe butonul din componenta copil să fie apelată funcția părintelui, care va modifica starea părintelui. Modificarea stării părintelui va declanșa rerandarea și va redesena produsul nostru, transmitându-i prop-ul modificat.
Luați componenta User din lecția anterioară.
Faceți astfel încât în ea să apară
un buton pentru banarea utilizatorului.