Vanhemman komponentin tilan muuttaminen lapsikomponentissa Reactissa
Edellisessä oppitunnissa tietotila sijoitettiin vanhemman komponentin sisään, ja lapsikomponentit saivat nämä tiedot propseina.
Oletetaan nyt, että haluamme muuttaa tuotteitamme.
Tehdään esimerkiksi painike, joka
laittaa tuotemme ostoskoriin. Aluksi
lisätään tuotematriisiimme
kenttä inCart, joka näyttää, onko tuote
ostoskorissa vai ei:
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},
];
Komponentissa Products tuotteen tagiin
lisätään toinen attribuutti 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>;
}
Tehdään lapsikomponentissa Product
ostoskoritiedon tulostus ja
painike ostoskoriin lisäämiseksi:
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>;
}
Toteutetaan lisäys
Reactin sääntojen mukaan komponentin ei pitäisi
muuttaa sen propseja. Tämä tarkoittaa, että
lapsikomponentti ei voi laittaa itse
itseään ostoskoriin muuttamalla propsia inCart.
Tämä on väärin.
Oikea tapa on pyytää vanhempakomponenttia
muuttamaan sen tilaa prods laittamalla
tietty tuote ostoskoriin.
Katsotaan kuinka se tehdään.
Vanhemmassakomponentissa tehdään funktio addToCart,
joka parametrina ottaa tuotteen id
ja muuttaa kyseisen tuotteen ominaisuuden inCart
arvoksi true:
function addToCart(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.inCart = true;
}
return prod;
}));
}
Tuotteen tagiin lisätään attribuutti, johon
annetaan luomamme funktio, sekä
attribuutti, johon annetaan tuotteen 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}
/>;
});
Kuten näette, komponenttien propseihin voidaan antaa ei vain tietoja, vaan myös funktioita.
Lopullinen Products-luokan koodi tulee
olemaan seuraava:
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>;
}
Nyt lapsiluokassa meillä on käytettävissä
funktio addToCart. Kutsutaan tätä funktiota
painikkeen klikkauksella, antamalla sille parametrina
tuotteen id:
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>;
}
Käy niin, että kun painiketta napsautetaan jälkikasvussa, kutsutaan vanhemman funktiota, joka muuttaa vanhemman tilan. Vanhemman tilan muuttaminen aiheuttaa uudelleenrenderöinnin ja piirtää uudelleen tuotteemme, antaen sille muutetun propin.
Ota komponentti User edellisestä
oppitunnista. Tee niin, että siihen ilmestyy
painike käyttäjän estämiseksi.