Komponentide alamkomponentide olekute kaudu töötamise režiimid Reactis

Oletame, et meie toodete massiiv näeb nüüd välja järgmiselt:

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

Kuvame need tooted HTML tabelina. Teeme seda nii, et klõpsates suvalisel tabeli lahtril, ilmuks sellesse lahtrisse sisestusväli redigeerimiseks. Ülesande lahendamiseks teeme 3 komponenti.

Komponent Products hoiab olekut toodetega ja kasutab komponente Product toodete kuvamiseks. Komponent Product omakorda kasutab ka komponente ProductField konkreetse toote välja kuvamiseks (nimi, hind, kategooria).

Komponent ProductField kuvab kas välja teksti või sisestusvälja selle redigeerimiseks. Samas režiim redigeerimine või kuvamine olgu reguleeritud selle komponendi olekuga.

See tähendab, et me ei salvesta režiimi vanema olekus. Seal oleks see väga ebamugav, kuna me peaksime määrama režiimi iga toode välja jaoks, mis muudaks meie oleku millegiks selliseks:

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

Me aga ei tee sellist olekut, vaid jätame selle, mis oli. Lihtsalt iga komponendi ProductField eksemplar oma oleku abil reguleerib režiimi: kas redigeerimine või kuvamine.

Seega selgub, et vanemkomponent salvestab olekus andmed, ja meie lapselapskomponent saab need andmed läbi propside ja samas omab oma olekut oma režiimi muutmiseks.

Nii, teostame kirjeldatu.

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

Praktilised ülesanded

Задание 1

Tehke samased toimingud komponentidega Users ja User, mille olete loonud eelmistes õppetundides.