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

Задание 1

Realiza operaciones similares con los componentes Users y User, creados por ti en lecciones anteriores.