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

← →
↑