Рэжымы працы праз стэйты кампанентаў-нашчадкаў у 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, створанымі вамі у папярэдніх уроках.