Режими рада преко стејтова компонената-потомака у React-у

Нека наш низ са производима сада изгледа следећим образом:

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

Хајде да прикажемо ове производе у виду HTML табеле. При томе ћемо урадити тако да при клику на било које ћелије табеле у тој ћелији се појави унос за измену. За решавање задатка ћемо направити 3 компоненте.

Компонента Products ће чувати стејт са производима и користити компоненте Product за приказ производа. Компонента Product заузврат ће такође користити компоненте ProductField за приказ одређеног поља производа (назива, цене, категорије).

Компонента ProductField ће или приказивати текст поља, или унос за његово мењање. При томе режим мењања или приказа нека регулише стејт ове компоненте.

То јест, нећемо чувати режим у родитељском стејту. Тамо би то било веома незгодно, јер би нам морало да назначимо режим за свако поље производа, што би наш стејт претворило у нешто попут овог:

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

Ми, међутим, нећемо правити такав стејт, већ ћемо оставити онај који је био. Једноставно, свака инстанца компоненте ProductField уз помоћ свог стејта ће регулисати режим: или мењање, или приказ.

Тако ће се испоставити да ће родитељска компонента чувати стејт са подацима, а наш унучади компонента ће примати те податке преко пропса и при томе ће имати сопствени стејт за промену свог режима.

Дакле, хајде да имплементирамо описано.

Компонента 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>;
}

Компонента 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>;
}

Компонента 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>;
}

Практични задаци

Задание 1

Поведите сличне операције са компонентама Users и User, које сте креирали у претходним лекцијама.