В предыдущем уроке у нас стейт с данными хранился в родительском компоненте, а дочерние компоненты получали эти данные в виде пропсов.
Пусть теперь мы хотим изменять наши продукты.
Сделаем, к примеру, кнопку, которая будет
помещать наш продукт в корзину. Для начала
давайте добавим в наш массив с продуктами
поле 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
из предыдущего
урока. Сделайте так, чтобы в нем появилась
кнопка для бана юзера.