Režimy práce prostredníctvom stavov podradených komponentov v Reacte

Nech náš pole s produktmi teraz vyzerá nasledovne:

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

Vypíšme tieto produkty vo forme HTML tabuľky. Zároveň spravme to, aby po kliknutí na ľubovoľnú bunku tabuľky sa v tejto bunke objavilo vstupné pole pre editáciu. Na vyriešenie úlohy urobme 3 komponenty.

Komponent Products bude uchovávať stav s produktmi a používať komponenty Product pre výpis produktov. Komponent Product naopak bude tiež používať komponenty ProductField pre výpis konkrétneho pola produktu (názvu, ceny, kategórie).

Komponent ProductField bude buď zobrazovať text poľa, alebo vstupné pole pre jeho editáciu. Pritom režim editácie alebo zobrazenia nech je regulovaný stavom daného komponentu.

To znamená, že režim nebudeme ukladať do nadradeného stavu. Tam by to bolo veľmi nepohodlné, pretože by sme museli uvádzať režim pre každé pole produktu, čo by premenilo náš stav na niečo podobné:

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

My však neurobíme takýto stav, ale ponecháme ten, ktorý bol. Jednoducho každá inštancia komponentu ProductField pomocou svojho stavu bude regulovať režim: buď editáciu, alebo zobrazenie.

Takto sa stane, že nadradený komponent bude uchovávať stav s údajmi, a náš vnorený komponent bude tieto údaje prijímať cez props a zároveň bude mať vlastný stav pre zmenu svojho režimu.

Takže, realizujme popísané.

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

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

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

Praktické úlohy

Задание 1

Vykonajte podobné operácie s komponentmi Users a User, ktoré ste vytvorili v predchádzajúcich lekciách.