Editando o estado do pai em um componente filho no React
Agora vamos editar nossos produtos usando inputs. Para isso, no componente filho, vamos criar um botão.
Ao primeiro clique neste botão, em vez do nome e preço do produto, devem aparecer inputs para editá-los, e ao segundo clique, em vez dos inputs, devem aparecer os textos novamente.
Vamos modificar o array de produtos, adicionando
a propriedade isEdit (e removeremos o trabalho com o carrinho
por simplicidade):
const initProds = [
{id: id(), name: 'product1', cost: 100, isEdit: false},
{id: id(), name: 'product2', cost: 200, isEdit: false},
{id: id(), name: 'product3', cost: 300, isEdit: false},
];
Componente Product
Vamos criar um botão de edição no produto:
function Product({ id, name, cost, isEdit }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button>edit</button>
</div>;
}
Vamos fazer com que, ao clicar neste botão,
uma função toggleMode seja chamada,
passada do componente pai:
function Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button onClick={() => toggleMode(id)}>
edit
</button>
</div>;
}
Ainda não temos a implementação de toggleMode,
mas sabemos que ela estará localizada
no componente pai, receberá o id
do produto como parâmetro e alterará a propriedade isEdit
do produto para o oposto.
Vamos também fazer com que o texto do botão mude a cada clique:
function Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button onClick={() => toggleMode(id)}>
{isEdit ? 'save': 'edit'}
</button>
</div>;
}
Agora vamos fazer com que no modo edição tenhamos inputs com os dados, e no modo normal - spans:
function Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
name: {isEdit ? <input value={name} /> : <span>{name}</span>}
cost: {isEdit ? <input value={cost} /> : <span>{cost}</span>}
<button onClick={() => toggleMode(id)}>
{isEdit ? 'save': 'edit'}
</button>
</div>;
}
Vamos vincular aos nossos inputs o evento onChange,
no qual chamaremos uma função do pai
editProd:
function Product({ id, name, cost, isEdit, toggleMode, editProd }) {
return <div>
name: {
isEdit
? <input value={name} onChange={event => editProd(id, 'name', event)} />
: <span>{ name }</span>
}
cost: {
isEdit
? <input value={cost} onChange={event => editProd(id, 'cost', event)} />
: <span>{ cost }</span>
}
<button onClick={() => toggleMode(id)}>
{isEdit ? 'save': 'edit'}
</button>
</div>;
}
Componente Products
Agora vamos para o componente Products.
Vamos implementar a função toggleMode nele:
function toggleMode(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.isEdit = !prod.isEdit;
}
return prod;
}));
}
Também implementaremos a função editProd nele:
function editProd(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
Na tag do produto, passaremos nossas
funções toggleMode e editProd como atributos:
const items = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name={prod.name}
cost={prod.cost}
isEdit={prod.isEdit}
toggleMode={toggleMode}
editProd={editProd}
/>;
});
O código final do componente Products
ficará da seguinte forma:
function Products() {
const [prods, setProds] = useState(initProds);
function toggleMode(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.isEdit = !prod.isEdit;
}
return prod;
}));
}
function editProd(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
const result = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name={prod.name}
cost={prod.cost}
isEdit={prod.isEdit}
toggleMode={toggleMode}
editProd={editProd}
/>;
});
return <div>
{result}
</div>;
}
Tarefas Práticas
Execute operações semelhantes com os componentes
Users e User, criados por você
nas lições anteriores.