Bearbeiten des Parent-State in einer Child-Komponente in React

Lass uns nun unsere Produkte mit Hilfe von Inputs bearbeiten. Dazu erstellen wir eine Schaltfläche in der Child-Komponente.

Beim ersten Klick auf diese Schaltfläche sollen anstelle des Namens und des Preises des Produkts Inputs zu deren Bearbeitung erscheinen, und beim zweiten Klick anstelle der Inputs wieder die Texte.

Nehmen wir eine Änderung im Produktarray vor, indem wir eine Eigenschaft isEdit hinzufügen (und der Einfachheit halber entfernen wir die Arbeit mit dem Warenkorb):

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},
];

Komponente Product

Erstellen wir eine Schaltfläche zur Bearbeitung im Produkt:

jsxfunction Product({ id, name, cost, isEdit }) {
  return <div>
    name: <span>{name}</span>
    cost: <span>{cost}</span>
    <button>edit</button>
  </div>;
}

Sorgen wir dafür, dass beim Klick auf diese Schaltfläche eine bestimmte Funktion toggleMode aufgerufen wird, die von der Parent-Komponente übergeben wird:

jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
  return <div>
    name: <span>{name}</span>
    cost: <span>{cost}</span>
    
    <button onClick={() => toggleMode(id)}>
      edit
    </button>
  </div>;
}

Noch haben wir keine Implementierung von toggleMode, aber wir wissen, dass sie sich in der Parent-Komponente befinden wird, die id des Produkts als Parameter entgegennimmt und die Eigenschaft isEdit des Produkts auf den gegenteiligen Wert setzt.

Sorgen wir auch dafür, dass sich der Text der Schaltfläche bei jedem Klick ändert:

jsxfunction 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>;
}

Lass uns nun dafür sorgen, dass im Bearbeitungsmodus Inputs mit den Daten angezeigt werden, und im normalen Modus - Spans:

jsxfunction 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>;
}

Binden wir an unsere Inputs das Ereignis onChange, in dem wir eine bestimmte Parent-Funktion editProd aufrufen werden:

jsxfunction 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>;
}

Komponente Products

Lass uns nun zur Komponente Products wechseln. Implementieren wir darin die Funktion toggleMode:

jsxfunction toggleMode(id) {
  setProds(prods.map(prod => {
    if (prod.id === id) {
      prod.isEdit = !prod.isEdit;
    }
    
    return prod;
  }));
}

Implementieren wir darin auch die Funktion editProd:

jsxfunction editProd(id, field, event) {
  setProds(prods.map(prod => {
    if (prod.id === id) {
      prod[field] = event.target.value;
    }
    
    return prod;
  }));
}

Übergeben wir unsere Funktionen toggleMode und editProd als Attribute im Produkt-Tag:

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}
  />;
});

Der endgültige Code der Komponente Products wird wie folgt aussehen:

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>;
}

Praktische Aufgaben

Задание 1

Führe ähnliche Operationen mit den Komponenten Users und User durch, die du in vorherigen Lektionen erstellt hast.