Vanema komponendi oleku muutmine lapse komponendis Reactis

Muudame nüüd oma tooteid sisendväljade abil. Selleks teeme lapse komponendis nupu.

Esimesel vajutusel sellele nupule kuvagu toote nime ja hinna asemel nende muutmiseks mõeldud sisendväljad, ning teisel vajutusel kuvagu sisendväljade asemel uuesti tekstid.

Teeme muudatuse tootemassiivis, lisades omaduse isEdit (ja ostukorvi töö eemaldame lihtsuse mõttes):

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

Komponent Product

Teeme tootes nupu muutmiseks:

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

Teeme nii, et selle nupu vajutamisel kutsutakse välja mingi funktsioon toggleMode, mis on edastatud vanemkomponendist:

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

Meil pole veel toggleMode rakendust, kuid me teame, et see asub vanemkomponendis, võtab parameetrina toote id ja muudab toote omadust isEdit vastupidiseks.

Teeme ka nii, et nupu tekst muutuks iga vajutusega:

jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
  return <div>
    nimi: <span>{name}</span>
    hind: <span>{cost}</span>
    
    <button onClick={() => toggleMode(id)}>
      {isEdit ? 'salvesta': 'muuda'}
    </button>
  </div>;
}

Teeme nüüd nii, et muutmise režiimis oleksid meil andmetega sisendväljad, ja tavarežiimis - span elemendid:

jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
  return <div>
    nimi: {isEdit ? <input value={name} /> : <span>{name}</span>}
    hind: {isEdit ? <input value={cost} /> : <span>{cost}</span>}
    
    <button onClick={() => toggleMode(id)}>
      {isEdit ? 'salvesta': 'muuda'}
    </button>
  </div>;
}

Seome oma sisendväljadega sündmuse onChange, milles kutsume välja mingi vanema funktsiooni editProd:

jsxfunction Product({ id, name, cost, isEdit, toggleMode, editProd }) {
  return <div>
    nimi: {
      isEdit
      ? <input value={name} onChange={event => editProd(id, 'name', event)} />
      : <span>{ name }</span>
    }
    hind: {
      isEdit
      ? <input value={cost} onChange={event => editProd(id, 'cost', event)} />
      : <span>{ cost }</span>
    }
    
    <button onClick={() => toggleMode(id)}>
      {isEdit ? 'salvesta': 'muuda'}
    </button>
  </div>;
}

Komponent Products

Liigume nüüd komponenti Products. Rakendame selles funktsiooni toggleMode:

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

Rakendame selles ka funktsiooni editProd:

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

Edastame oma funktsioonid toggleMode ja editProd toote elemendile atribuutidena:

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

Komponendi Products lõplik kood saab järgmiseks:

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

Praktilised ülesanded

Задание 1

Tehke samasugused toimingud komponentidega Users ja User, mille te loosite eelmistes õppetundides.