Ændring af forældrekomponentens state i et underkomponent i React
I den forrige lektion havde vi en state med data gemt i forældrekomponenten, mens underkomponenterne modtog disse data som props.
Lad os nu sige, at vi ønsker at ændre vores produkter.
Lad os for eksempel lave en knap, som vil
placere vores produkt i indkøbskurven. Til at starte med,
lad os tilføje et felt inCart til vores array med produkter,
som viser om produktet er i indkøbskurven eller ej:
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 tilføjer vi endnu en attribut inCart
i tagget med produktet:
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>;
}
Lad os i underkomponentet Product
lave en udskrift af information om indkøbskurven og en knap
til at tilføje til indkøbskurven:
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>;
}
Implementer tilføjelsen
Ifølge Reacts regler må en komponent ikke
ændre sine egne props. Det betyder, at
underkomponentet ikke selv kan lægge
sig selv i indkøbskurven ved at ændre prop'en inCart.
Det er ikke korrekt.
Korrekt vil være at bede forældrekomponenten om at
ændre sin state prods, ved at lægge
et bestemt produkt i indkøbskurven.
Lad os se på, hvordan det gøres.
I forældrekomponenten laver vi en funktion addToCart,
som tager et id for produktet som parameter
og for dette produkt ændrer egenskaben inCart
til true:
function addToCart(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.inCart = true;
}
return prod;
}));
}
I tagget med produktet tilføjer vi en attribut, hvori
vi sender den funktion, vi har oprettet, samt
en attribut, hvori vi sender produktets 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 du kan se, kan man i komponenters props sende ikke kun data, men også funktioner.
Den endelige kode for klassen Products vil blive
følgende:
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 vil funktionen addToCart være tilgængelig i underklassen.
Lad os kalde denne funktion
ved et klik på knappen, ved at sende den id for produktet 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>;
}
Resultatet bliver, at ved et klik på knappen i underkomponentet kaldes forælderens funktion, som vil ændre forælderens state. Ændring af forælderens state vil udløse en genrendering og gen tegne vores produkt, ved at sende den den ændrede prop.
Tag komponentet User fra den forrige
lektion. Lav det sådan, at der vises en knap for at banlyse en bruger.