Ändra föräldrakomponentens state i en barnkomponent i React
I föregående lektion hade vi state med data lagrat i föräldrakomponenten, medan barnkomponenterna fick dessa data som props.
Låt oss nu säga att vi vill ändra våra produkter.
Låt oss göra en knapp till exempel som kommer att
lägga vår produkt i varukorgen. Till att börja med
låt oss lägga till ett fält inCart i vår array med produkter
som visar om produkten är i varukorgen eller inte:
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},
];
I komponenten Products lägger vi till ytterligare ett attribut inCart
i taggen med produkten:
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>;
}
Låt oss i barnkomponenten Product
göra en utskrift av information om varukorgen och en knapp
för att lägga till i varukorgen:
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>;
}
Implementera tillägget
Enligt Reacts regler får en komponent inte
ändra sina props. Det betyder att
barnkomponenten inte kan lägga sig själv
i varukorgen genom att ändra prop inCart.
Det är inte korrekt.
Korrekt är att be föräldrakomponenten
ändra sitt state prods genom att lägga
en specifik produkt i varukorgen.
Låt oss titta på hur detta görs.
I föräldrakomponenten skapar vi en funktion addToCart,
som tar ett id för produkten som parameter
och för den produkten ändrar egenskapen inCart
till true:
function addToCart(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.inCart = true;
}
return prod;
}));
}
I taggen med produkten lägger vi till ett attribut, där vi
skickar funktionen vi skapat, samt
ett attribut, där vi skickar produktens id:
const items = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name ={prod.name}
cost ={prod.cost}
inCart ={prod.inCart}
addToCart={addToCart}
/>;
});
Som ni ser kan man i komponenters props skicka inte bara data, utan även funktioner.
Den slutgiltiga koden för klassen Products kommer att bli
följande:
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>;
}
Nu i barnklassen kommer vi att ha tillgång till
funktionen addToCart. Låt oss anropa denna funktion
vid klick på knappen, och skicka med produktens
id som parameter:
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>;
}
Det kommer att resultera i att vid klick på knappen i barnkomponenten anropas förälderns funktion, som kommer att ändra förälderns state. Förändringen av förälderns state kommer att orsaka en omrendering och kommer att rita om vår produkt, och skicka med den ändrade proppen.
Ta komponenten User från föregående
lektion. Gör så att en knapp för att banna användaren
dyker upp i den.