Edición del estado del padre en un componente hijo en React
Ahora vamos a editar nuestros productos usando inputs. Para ello, en el componente hijo hagamos un botón.
Al primer clic en este botón, que en lugar del nombre y precio del producto aparezcan inputs para su edición, y al segundo clic en lugar de los inputs aparezcan nuevamente los textos.
Hagamos un cambio en el array de productos, agregando
la propiedad isEdit (y eliminaremos el trabajo con el carrito
por simplicidad):
jsxconst 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
Hagamos en el producto un botón para editar:
jsxfunction Product({ id, name, cost, isEdit }) {
return <div>
nombre: <span>{name}</span>
precio: <span>{cost}</span>
<button>editar</button>
</div>;
}
Hagamos que al hacer clic en este botón
se llame a alguna función toggleMode,
pasada desde el componente padre:
jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
nombre: <span>{name}</span>
precio: <span>{cost}</span>
<button onClick={() => toggleMode(id)}>
editar
</button>
</div>;
}
Aún no tenemos la implementación de toggleMode,
pero sabemos que estará ubicada
en el componente padre, recibirá como parámetro
el id del producto y cambiará la propiedad isEdit
del producto al valor opuesto.
Hagamos también que el texto del botón cambie en cada clic:
jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
nombre: <span>{name}</span>
precio: <span>{cost}</span>
<button onClick={() => toggleMode(id)}>
{isEdit ? 'guardar': 'editar'}
</button>
</div>;
}
Ahora hagamos que en el modo de edición tengamos inputs con los datos, y en el modo normal - spans:
jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
return <div>
nombre: {isEdit ? <input value={name} /> : <span>{name}</span>}
precio: {isEdit ? <input value={cost} /> : <span>{cost}</span>}
<button onClick={() => toggleMode(id)}>
{isEdit ? 'guardar': 'editar'}
</button>
</div>;
}
Asociemos a nuestros inputs el evento onChange,
en el cual llamaremos a alguna función parental
editProd:
jsxfunction Product({ id, name, cost, isEdit, toggleMode, editProd }) {
return <div>
nombre: {
isEdit
? <input value={name} onChange={event => editProd(id, 'name', event)} />
: <span>{ name }</span>
}
precio: {
isEdit
? <input value={cost} onChange={event => editProd(id, 'cost', event)} />
: <span>{ cost }</span>
}
<button onClick={() => toggleMode(id)}>
{isEdit ? 'guardar': 'editar'}
</button>
</div>;
}
Componente Products
Ahora pasemos al componente Products.
Implementemos en él la función toggleMode:
jsxfunction toggleMode(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.isEdit = !prod.isEdit;
}
return prod;
}));
}
También implementemos en él la función editProd:
jsxfunction editProd(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
En la etiqueta del producto pasemos como atributos nuestras
funciones toggleMode y editProd:
jsxconst 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}
/>;
});
El código final del componente Products
será el siguiente:
jsxfunction 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>;
}
Tareas prácticas
Realiza operaciones similares con los componentes
Users y User, creados por ti
en lecciones anteriores.