Modos de trabajo a través de estados en componentes hijos en React
Supongamos que nuestro array de productos ahora luce de la siguiente manera:
const initProds = [
{id: id(), name: 'prod1', cost: 'cost1', catg: 'catg1'},
{id: id(), name: 'prod2', cost: 'cost2', catg: 'catg2'},
{id: id(), name: 'prod3', cost: 'cost3', catg: 'catg3'},
];
Vamos a mostrar estos productos en forma de tabla HTML.
Al mismo tiempo, hagamos que al hacer clic en cualquier
celda de la tabla aparezca un input para editar. Para
resolver la tarea crearemos 3 componentes.
El componente Products almacenará el estado
con los productos y utilizará componentes Product
para mostrar los productos. El componente Product
a su vez también utilizará componentes
ProductField para mostrar un campo específico
del producto (nombre, precio, categoría).
El componente ProductField mostrará ya sea
el texto del campo, o un input para editarlo.
Al mismo tiempo, que el modo de edición
o visualización se regule mediante el estado
de este componente.
Es decir, no almacenaremos el modo en el estado padre. Allí sería muy inconveniente, ya que tendríamos que especificar el modo para cada campo del producto, lo que convertiría nuestro estado en algo similar a esto:
const initProds = [
[
{field: 'name', value: 'prod1', isEdit: false},
{field: 'cost', value: 'cost1', isEdit: false},
{field: 'catg', value: 'catg1', isEdit: false},
],
[
{field: 'name', value: 'prod2', isEdit: false},
{field: 'cost', value: 'cost2', isEdit: false},
{field: 'catg', value: 'catg2', isEdit: false},
],
[
{field: 'name', value: 'prod3', isEdit: false},
{field: 'cost', value: 'cost3', isEdit: false},
{field: 'catg', value: 'catg3', isEdit: false},
],
]
Sin embargo, no crearemos dicho estado,
sino que mantendremos el que teníamos.
Simplemente cada instancia del componente ProductField
mediante su propio estado regulará el modo:
edición o visualización.
De este modo, resultará que el componente padre almacenará el estado con los datos, y nuestro componente nieto recibirá estos datos a través de props y al mismo tiempo tendrá su propio estado para cambiar su modo.
Entonces, implementemos lo descrito.
Componente Products
function Products() {
const [prods, setProds] = useState(initProds);
function changeField(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
const rows = prods.map(prod => {
return <Product
key ={prod.id}
id ={prod.id}
name={prod.name}
cost={prod.cost}
catg={prod.catg}
changeField={changeField}
/>;
});
return <div>
<table>
<tbody>
{rows}
</tbody>
</table>
</div>;
}
Componente Product
function Product({ id, name, cost, catg, changeField }) {
return <tr>
<ProductField id={id} text={name} type="name" changeField={changeField} />
<ProductField id={id} text={cost} type="cost" changeField={changeField} />
<ProductField id={id} text={catg} type="catg" changeField={changeField} />
</tr>;
}
Componente ProductField
function ProductField({ id, text, type, changeField }) {
const [isEdit, setIsEdit] = useState(false);
return <td>
{
isEdit
? <input
value={text}
onChange={event => changeField(id, type, event)}
onBlur={() => setIsEdit(false)}
/>
: <span onClick={() => setIsEdit(true)}>{text}</span>
}
</td>;
}
Tareas prácticas
Realice operaciones similares con los componentes
Users y User, creados por usted
en lecciones anteriores.