Επεξεργασία της κατάστασης του γονέα στο θυγατρικό στοιχείο στο React

Ας επεξεργαστούμε τώρα τα προϊόντα μας χρησιμοποιώντας πεδία εισαγωγής. Για αυτό, στο θυγατρικό στοιχείο ας δημιουργήσουμε ένα κουμπί.

Στο πρώτο πάτημα αυτού του κουμπιού ας εμφανιστούν πεδία εισαγωγής για την επεξεργασία τους αντί για το όνομα και την τιμή του προϊόντος, και στο δεύτερο πάτημα ας εμφανιστούν ξανά τα κείμενα αντί για τα πεδία εισαγωγής.

Ας κάνουμε αλλαγή στον πίνακα με τα προϊόντα, προσθέτοντας την ιδιότητα isEdit (και για απλότητα ας αφαιρέσουμε τη δουλειά με το καλάθι):

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

Στοιχείο Product

Ας δημιουργήσουμε ένα κουμπί για επεξεργασία στο προϊόν:

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

Ας κάνουμε έτσι ώστε με το κλικ σε αυτό το κουμπί να καλείται κάποια συνάρτηση toggleMode, που μεταβιβάζεται από το γονικό στοιχείο:

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

Προς το παρόν δεν έχουμε υλοποίηση της toggleMode, αλλά ξέρουμε ότι θα βρίσκεται στο γονικό στοιχείο, θα δέχεται ως παράμετρο το id του προϊόντος και θα αλλάζει την ιδιότητα isEdit του προϊόντος στο αντίθετο.

Ας κάνουμε επίσης έτσι ώστε το κείμενο του κουμπιού να αλλάζει σε κάθε πάτημα:

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

Ας κάνουμε τώρα έτσι ώστε στη λειτουργία επεξεργασίας να έχουμε πεδία εισαγωγής με τα δεδομένα, και στη συνηθισμένη λειτουργία - 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>;
}

Ας δέσουμε στα πεδία εισαγωγής μας το συμβάν onChange, στο οποίο θα καλούμε κάποια γονική συνάρτηση editProd:

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

Στοιχείο Products

Ας πάμε τώρα στο στοιχείο Products. Ας υλοποιήσουμε σε αυτό τη συνάρτηση toggleMode:

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

Επίσης ας υλοποιήσουμε σε αυτό τη συνάρτηση editProd:

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

Στη ετικέτα με το προϊόν ως χαρακτηριστικά θα μεταβιβάσουμε τις συναρτήσεις μας toggleMode και 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}
  />;
});

Ο τελικός κώδικας του στοιχείου Products θα είναι ο ακόλουθος:

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

Πρακτικές Ασκήσεις

Задание 1

Εκτελέστε παρόμοιες λειτουργίες με τα στοιχεία Users και User, που δημιουργήσατε σε προηγούμενα μαθήματα.