Načini delovanja preko stanj komponent-potomcev v React

Naj bo naš seznam izdelkov zdaj videti takole:

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

Izpišimo te izdelke v obliki HTML tabele. Pri tem naredimo tako, da se ob kliku na katero koli celico tabele v tej celici pojavi vnosno polje za urejanje. Za rešitev naloge naredimo 3 komponente.

Komponenta Products bo hranila stanje z izdelki in uporabljala komponente Product za prikaz izdelkov. Komponenta Product bo prav tako uporabljala komponente ProductField za prikaz določenega polja izdelka (ime, cena, kategorija).

Komponenta ProductField bo pokazala bodisi besedilo polja bodisi vnosno polje za njegovo urejanje. Pri tem naj se način urejanja ali prikaza regulira s stanjem te komponente.

To pomeni, da načina ne bomo hranili v nadrejenem stanju. Tam bi bilo to zelo neprijetno, saj bi morali navesti način za vsako polje izdelka, kar bi spremenilo naše stanje v nekaj podobnega:

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

Vendar mi ne bomo naredili takšnega stanja, ampak bomo obdržali tistega, ki je bil. Preprosto bo vsak primer komponente ProductField s pomočjo svojega stanja reguliral način: bodisi urejanje, bodisi prikaz.

Tako se bo izkazalo, da bo nadrejena komponenta hranila stanje s podatki, naša vnukinja komponenta pa bo te podatke prejela preko propov in bo imela svoje stanje za spreminjanje svojega načina.

Torej, implementirajmo opisano.

Komponenta Products

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

Komponenta Product

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

Komponenta ProductField

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

Praktične naloge

Задание 1

Izvedite podobne operacije s komponentami Users in User, ki ste jih ustvarili v prejšnjih lekcijah.