Промяна на състоянието на родителя в детски компонент в React
В предишния урок нашето състояние с данни беше съхранено в родителския компонент, а детските компоненти получаваха тези данни под формата на пропсове.
Нека сега искаме да променяме нашите продукти.
Нека направим, например, бутон, който ще
поставя нашия продукт в количката. Като начало
нека добавим в нашия масив с продукти
поле inCart, показващо дали продуктът
е в количката или не:
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},
];
В компонента Products в тага с продукта
добавяме още един атрибут 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>;
}
Нека в детския компонент Product
направим извеждане на информация за количката и бутон
за добавяне в количката:
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>;
}
Реализираме добавянето
По правилата на React компонентът не трябва
да променя своите пропсове. Това означава, че
детският компонент не може да се сложи сам
в количката, като промени пропса inCart.
Това не е правилно.
Правилно ще бъде да помолим родителския компонент
да промени своето състояние prods, като сложи
определен продукт в количката.
Нека да видим как се прави това.
В компонента-родител направим функция addToCart,
която параметър приема id на продукта
и за този продукт променя свойството inCart
на true:
function addToCart(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.inCart = true;
}
return prod;
}));
}
В тага с продукта добавяме атрибут, в който
предаваме създадената от нас функция, както и
атрибут, в който предаваме 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}
/>;
});
Както виждате, в пропсовете на компонентите може да се предават не само някакви данни, но и функции.
Крайният код на класа Products ще се получи
следният:
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>;
}
Сега в детския клас ще имаме достъпна
функцията addToCart. Извикваме тази функция
при кликване на бутона, като й подаваме параметър
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>;
}
Получава се, че при кликване на бутона в потомъка ще се извика функция на родителя, която ще промени родителското състояние. Промяната на родителското състояние ще предизвика пререндериране и ще прерисува нашия продукт, като му предаде променения пропс.
Вземете компонента User от предишния
урок. Направете така, че в него да се появи
бутон за бан на потребителя.